import sys import pickle import subprocess import tkinter as tk import ttkbootstrap as ttk from tkinter import messagebox import tkinter.scrolledtext as st from ttkbootstrap import * from PIL import Image, ImageTk from tkinter import Canvas, Frame, BOTH, PhotoImage, filedialog from X3 import load_data from X2 import ModelObj,connect_class # 网络模型正确的图元和连接关系的数据结构,用一个数组表示 RIGHT_MODEL = [ [0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1], [0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0] ] # 创建三个空的卷积层图元实例和三个空的全连接层图元实例 Conv1 = None Conv2 = None Conv3 = None Pool1 = None Pool2 = None Pool3 = None Fullconn1 = None Fullconn2 = None Fullconn3 = None global Viewcanvas # 定义画布 global Text # 带滚动条 global Root # 主窗口 global AllModelObj #网络对象 List_image = [] # 存储图元的列表 Prob_images = [] # 存储图元的列表 Train_images = [] # 存储训练集的列表 Test_images = [] # 存储测试集的列表 Items1 = [] # 存储新图元的列表 Items2 = [] # 存储新数据线的列表 Items3 = [] # 存储被拖拽的图元的列表 Items4 = [] # 存储新图元文字标签的列表 Counts = {} # 用来存储Items3每个数字出现过的次数 Conv_xy_list = [] # 存储卷积图元的坐标 Fullconn_xy_list = [] # 存储全连接图元的坐标 Train_list = [] # 存储训练设置参数 Listinstance = [] # 图元对象实例 Dragged_item = () # 记录被拖拽的图元id Original_x = 0 # 记录图元原来的x坐标 Original_y = 0 # 记录图元原来的y坐标 Offset_x = 0 # 记录鼠标相对于图元的x偏移量 Offset_y = 0 # 记录鼠标相对于图元的y偏移量 Yt = 0 # 新图元的y坐标 Batch = 0 #批次 def create_instance(): # 创建图元对象实例 DataSet = ModelObj("DataSet", 1, "数据集", "LoadData", "SetDataPara", ".", 120, 70).output() Conv = ModelObj("Conv", 2, "卷积", "ConvProc", "SetConvPara", ".", 280, 70).output() Pool = ModelObj("Pool", 3, "最大池化", "MaxPoolProc", "SetPollPara", ".", 120, 165).output() FullConn = ModelObj("FullConn", 4, "全连接", "FullConnProc", "SetFullConnPara", ".", 280, 165).output() Nonline = ModelObj("Nonline", 5, "非线性函数", "NonlinearProc", "SetNonLPara", ".", 120, 260).output() Classifier = ModelObj("Classifier", 6, "分类", "ClassifierProc", "SetClassifyPara", ".", 280, 260).output() Error = ModelObj("Error", 7, "误差计算", "ErrorProc", "SetErrorPara", ".", 120, 355).output() AjConv = ModelObj("AjConv", 8, "卷积调整", "AjConvProc", "SetAjConvPara", ".", 280, 355).output() AjFullconn = ModelObj("AjFullconn", 9, "全连接调整", "AjFullconnProc", "SetAjFCPara", ".", 120, 450).output() AjNonline = ModelObj("AjNonline", 10, "非线性调整", "AjNonlineProc", "SetAjNLPara", ".", 280, 450).output() listinstance = [DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn, AjNonline] return listinstance # 还回图元对象实例列表 def picture_frame(window_width,window_height): gap = 20 # 设置矩形框之间的间隔为10像素 # 计算矩形框的坐标和尺寸 rect1_x = gap # 第一个矩形框的左上角x坐标 rect1_y = gap # 第一个矩形框的左上角y坐标 rect1_width = window_width * 1 / 3 - gap-50 # 第一个矩形框的宽度 rect1_height = window_height * 3 / 4 - gap * 2-50 # 第一个矩形框的高度 rect2_x = window_width * 1 / 3 + gap - 50 # 第二个矩形框的左上角x坐标 rect2_y = gap # 第二个矩形框的左上角y坐标 rect2_width = window_width * 2 / 3 - gap + 50 # 第二个矩形框的宽度 rect2_height = window_height * 3 / 4 - gap * 2 -50 # 第二个矩形框的高度 rect3_x = gap # 第三个矩形框的左上角x坐标 rect3_y = window_height * 3 / 4 + gap - 50 # 第三个矩形框的左上角y坐标 rect3_width = window_width - gap * 2 # 第三个矩形框的宽度 rect3_height = window_height * 1 / 4 - gap * 2 + 50 # 第三个矩形框的高度 global Viewcanvas # 创建一个画布,用于绘制矩形框,设置画布的大小和背景色 Viewcanvas = tk.Canvas(Root, width=window_width, height=window_height, bg="blue") Viewcanvas.pack() # 将画布添加到主窗口中 # 绘制矩形框,使用不同的颜色和线宽,指定矩形框的左上角和右下角坐标,填充色,边框色和边框宽度 Viewcanvas.create_rectangle(rect1_x, rect1_y, rect1_x + rect1_width, rect1_y + rect1_height, fill=None, outline="lightblue", width=2) Viewcanvas.create_rectangle(rect2_x, rect2_y + 20, rect2_x + rect2_width - 20, rect2_y + rect2_height, fill=None, outline="lightblue", width=2) Viewcanvas.create_rectangle(rect3_x, rect3_y, rect3_x + rect3_width, rect3_y + rect3_height, fill=None, outline="lightblue", width=2) global Text Text = st.ScrolledText(Root) # 创建一个带滚动条的文本框,用于展示计算过程 Text.place(x=rect3_x, y=rect3_y, width=1160, height=rect3_height - 1) # if __name__ == '__main__': # Root = tk.Tk() # # 设置窗口的大小为1200*750 # window_width = 1200 # 窗口的宽度 # window_height = 750 # 窗口的高度 # Root.title("神经网络可视化") # Root.geometry("1200x750") # 设置窗口的大小和位置 # picture_frame(window_width, window_height) # Root.mainloop() def element(path): # 加载图元对应的图片文件 img=Image.open(path) # 使用resize方法调整图片 img = img.resize((70, 60)) # 把Image对象转换成PhotoImage对象 img = ImageTk.PhotoImage(img) # 保存图片的引用,防止被垃圾回收 Root.img = img return img def push_button(): button = {} # 指定按钮主题为 litera style = Style(theme='litera') # 设置blue.TButton样式的背景色为亮蓝灰,前景色为白色 style.configure("blue.TButton", background="LightSlateGray", foreground="white", font=("黑体", 13)) style.map("blue.TButton", background=[('active', 'PowderBlue'), ('pressed', 'red')], # 设置激活状态下的背景色为粉蓝色,按下状态下的背景色为红色 foreground=[('active', 'black'), ('pressed', 'white')]) # 设置激活状态下的前景色为黑色,按下状态下的前景色为白色 # 设置green.TButton样式的背景色为中海洋绿,前景色为白色 style.configure("green.TButton", background="MediumSeaGreen", foreground="white", font=("黑体", 13)) style.map("green.TButton", background=[('active', 'PaleGreen'), ('pressed', 'red')], # 设置激活状态下的背景色为弱绿色,按下状态下的背景色为红色 foreground=[('active', 'black'), ('pressed', 'white')]) # 设置激活状态下的前景色为黑色,按下状态下的前景色为白色 # 创建三个按钮,用于触发训练参数的设置、训练、输出模型程序的操作 button1 = ttk.Button(Root, text=" 训练参数设置 ", style="blue.TButton") button1.place(x=20, y=500) button['button1'] = button1 button2 = ttk.Button(Root, text=" 训练 ", style="blue.TButton") button2.place(x=190, y=500) button['button2'] = button2 button3 = ttk.Button(Root, text=" 输出模型程序 ", style="blue.TButton") button3.place(x=300, y=500) button['button3'] = button3 # 创建五个按钮,用于触发操作 button4 = ttk.Button(Root, text=" 加载已有模型 ", style="green.TButton") button4.place(x=370, y=5) button['button4'] = button4 button5 = ttk.Button(Root, text=" 新建模型 ", style="green.TButton") button5.place(x=530, y=5) button['button5'] = button5 button6 = ttk.Button(Root, text=" 图元参数设置 ", style="green.TButton") button6.place(x=660, y=5) button['button6'] = button6 button7 = ttk.Button(Root, text=" 保存模型 ", style="green.TButton") button7.place(x=820, y=5) button['button7'] = button7 button8 = ttk.Button(Root, text=" 模型正确性检查 ", style="green.TButton") button8.place(x=940, y=5) button['button8'] = button8 button9 = ttk.Button(Root, text="退出", style="green.TButton") button9.place(x=1120, y=5) button['button9'] = button9 return button def setload_data(): # 设置数据集路径信息 train_imgPath = filedialog.askdirectory(title="请选择训练集") + "/" # 训练集文件夹的位置 test_imgPath = filedialog.askdirectory(title="请选择测试集") + "/" # 测试集文件夹的位置 # 设置图片大小 img_width = 48 # 图片宽度 img_height = 48 # 图片高度 # 设置每批次读入图片的数量 batch_size = 32 # 批次大小 # 返回DataPara参数,这里用一个字典来存储 DataPara = {"train_imgPath": train_imgPath, "test_imgPath": test_imgPath, "img_width": img_width, "img_height": img_height, "batch_size": batch_size} return DataPara # 定义图元拖拽开始的函数 def on_drag_start(event): global Dragged_item # 记录被拖拽的图元id global Original_x # 记录图元原来的x坐标 global Original_y # 记录图元原来的y坐标 global Offset_x # 记录鼠标相对于图元的x偏移量 global Offset_y # 记录鼠标相对于图元的y偏移量 # 获取当前图元的id # 这个物体的id是由tkinter自动分配的。当在画布上创建一个物体时,它会返回一个唯一的整数id,可以用它来引用这个物体 Dragged_item = event.widget.find_closest(event.x, event.y) Original_x = event.widget.coords(Dragged_item)[0] # 获取当前图元的x坐标 Original_y = event.widget.coords(Dragged_item)[1] # 获取当前图元的y坐标 Offset_x = Original_x - event.x # 计算鼠标相对于图元的x偏移量 Offset_y = Original_y - event.y # 计算鼠标相对于图元的y偏移量 # 定义图元拖拽移动的函数 def on_drag_motion(event): x = event.x + Offset_x # 计算图元新的x坐标 y = event.y + Offset_y # 计算图元新的y坐标 event.widget.coords(Dragged_item, x, y) # 更新图元的位置 def entity_loading_dataset(event): global Viewcanvas x = event.x + Offset_x y = event.y + Offset_y Items3.append(0) # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 new_item1 = Viewcanvas.create_image(x, y, image=List_image[0]) # 复制一个图片,表示数据集1 Viewcanvas.create_text(x, y + 45, text='数据集')# 复制图元对象的标签 event.widget.coords(Dragged_item, Original_x, Original_y)# 恢复图元的原位置 Items1.append((new_item1, x, y))# 将新图元的id和坐标添加到列表中 global Yt Items_y = Items1[0] # 将新图元的y坐标取出,方便后续图元水平排列 Yt = Items_y[2] # 创建一个tkinter根窗口,并隐藏它 root1 = tk.Tk() root1.withdraw() DataPara = setload_data() # 调用X3中setload_data()函数,获取加载数据集的参数 global Train_images global Test_images Train_images, Test_images = load_data(DataPara) # 调用X3中load_data()函数,根据参数加载数据集 # 打印一些信息,检查是否正确加载 print("训练集图片的形状:", Train_images.shape) print("测试集图片的形状:", Test_images.shape) # 创建弹出窗口 def creat_window(title): top = tk.Toplevel(Root) top.geometry("300x350") top.title(title) return top # 输入框 def create_input_box(top, text,value): box_label = tk.Label(top, text=text) box_label.pack(padx=10, pady=10) box_size = tk.IntVar(top, value=value) # 创建一个IntVar对象,并设置默认值为3 box_size_entry = tk.Entry(top, textvariable=box_size) # 关联IntVar对象 box_size_entry.pack(padx=20, pady=20) return box_size_entry # 下拉框 def create_dropdown_box(top, text, listvalues): # 创建一个下拉框,用于选择 box_mode_label = tk.Label(top, text=text) box_mode_label.pack(padx=10, pady=10) box_mode_combobox = ttk.Combobox(top) box_mode_combobox["values"] = listvalues box_mode_combobox.pack(padx=20, pady=15) return box_mode_combobox def convolution(event): global Items3 global Viewcanvas x = event.x + Offset_x Items3.append(1) # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 new_item1 = Viewcanvas.create_image(x, Yt, image=List_image[1]) # 复制一个图片,表示卷积层 event.widget.coords(Dragged_item, Original_x, Original_y) # 恢复图元的原位置 Items1.append((new_item1, x, Yt)) # 将新图元的id和坐标添加到列表中 top = creat_window('卷积参数配置') # 创建弹出窗口 kernel_size_entry = create_input_box(top,"卷积核大小:",3) # 创建一个输入框,获取卷积核大小 stride_entry = create_input_box(top,"卷积核大小:",1) # 创建一个输入框,获取卷积步长 def get_input(): # 创建 global Listinstance result1 = int(kernel_size_entry.get())# 获取输入框的内容 result2 = int(stride_entry.get()) Viewcanvas.create_text(x, Yt + 40, text=str(result1) + "*" + str(result1) + "卷积") # 创建图元对象的标签 if Listinstance[1][5] == ".": Listinstance[1][5] = str(result1) + "," + str(result2) else: Listinstance[1][5] = Listinstance[1][5] + " " + str(result1) + "," + str(result2) top.destroy()# 关闭窗口 button = tk.Button(top, text="获取信息", command=get_input) button.pack() def pooling(event): global Items3 global Viewcanvas x = event.x + Offset_x # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 Items3.append(2) # 复制一个图片,表示池化层 new_item1 = Viewcanvas.create_image(x, Yt, image=List_image[2]) # 恢复图元的原位置 event.widget.coords(Dragged_item, Original_x, Original_y) # 将新图元的id和坐标添加到列表中 Items1.append((new_item1, x, Yt)) # 创建弹出窗口 top=creat_window("池化参数配置") pool_type_combobox=create_dropdown_box(top, "池化池类型:", ["max", "avg", "min"])# 创建一个下拉框,用于选择池化类型 pool_size_entry = create_input_box(top, "池化池大小:", 2)# 创建一个输入框,用于输入池大小 # 创建 def get_input(): # 从下拉框中获取池化类型 pool_type = pool_type_combobox.get() # 从输入框中获取池大小 pool_size = int(pool_size_entry.get()) # 复制对象的标签 Viewcanvas.create_text(x, Yt + 40, text=str(pool_size) + "*" + str(pool_size) + str(pool_type) + "池化") if Listinstance[2][5] == ".": Listinstance[2][5] = str(pool_type) + "," + str(pool_size) else: Listinstance[2][5] = Listinstance[2][5] + " " + str(pool_type) + "," + str(pool_size) # 关闭窗口 top.destroy() button = tk.Button(top, text="获取信息", command=get_input) button.pack() def fully_connected(event): global Items3 global Viewcanvas x = event.x + Offset_x # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 Items3.append(3) # 复制一个图片,表示全连接层 new_item1 = Viewcanvas.create_image(x, Yt, image=List_image[3]) # 恢复图元的原位置 event.widget.coords(Dragged_item, Original_x, Original_y) # 将新图元的id和坐标添加到列表中 Items1.append((new_item1, x, Yt)) # 创建弹出窗口 top = creat_window("全连接参数配置") fully_size_entry = create_input_box(top, "全连接输出维度:", 10) # 创建一个输入框,用于输入池大小 # 创建 def get_input(): global Listinstance # 从下拉框中获取输出维度 num = int(fully_size_entry.get()) # 复制对象的标签 Viewcanvas.create_text(x, Yt + 40, text=str(num) + "--全连接") if Listinstance[3][5] == ".": Listinstance[3][5] = str(num) else: Listinstance[3][5] = Listinstance[3][5] + " " + str(num) # 关闭窗口 top.destroy() button = tk.Button(top, text="获取信息", command=get_input) button.pack(padx=20, pady=50) def nonlinear(event): global Items3 global Viewcanvas x = event.x + Offset_x # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 Items3.append(4) # 复制一个图片,表示非线性函数图元 new_item1 = Viewcanvas.create_image(x, Yt, image=List_image[4]) # 恢复图元的原位置 event.widget.coords(Dragged_item, Original_x, Original_y) # 将新图元的id和坐标添加到列表中 Items1.append((new_item1, x, Yt)) top = creat_window('非线性参数配置') # 创建弹出窗口 # 创建一个下拉框,用于选择非线性类型 nonlinear_mode_combobox = create_dropdown_box(top, "非线性类型", ["Sigmoid", "ReLU", "Tanh"])# 创建一个下拉框,用于选择池化类型 # 创建 def get_input(): global Listinstance # 从下拉框中获取池化类型 nonlinear_mode = nonlinear_mode_combobox.get() # 复制对象的标签 Viewcanvas.create_text(x, Yt + 40, text=str(nonlinear_mode) + "处理") if Listinstance[4][5] == ".": Listinstance[4][5] = str(nonlinear_mode) else: Listinstance[4][5] = Listinstance[4][5] + " " + str(nonlinear_mode) # 关闭窗口 top.destroy() button = tk.Button(top, text="获取信息", command=get_input) button.pack() def class_ification(event): global Listinstance global Viewcanvas global Items3 x = event.x + Offset_x # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 Items3.append(5) # 复制一个图片,表示分类器 new_item1 = Viewcanvas.create_image(x, Yt, image=List_image[5]) # 恢复图元的原位置 event.widget.coords(Dragged_item, Original_x, Original_y) # 将新图元的id和坐标添加到列表中 Items1.append((new_item1, x, Yt)) top = creat_window("分类参数配置") class_size_entry = create_input_box(top, "阈值:", 0.001) # 创建一个输入框,用于分类大小 # 创建 def get_input(): # 从输入框中获取阈值 threshold = float(class_size_entry.get()) # 复制对象的标签 Viewcanvas.create_text(x, Yt + 40, text="输出分类结果") if Listinstance[5][5] == ".": Listinstance[5][5] = str(threshold) else: Listinstance[5][5] = Listinstance[5][5] + " " + str(threshold) # 关闭窗口 top.destroy() button = tk.Button(top, text="获取信息", command=get_input) button.pack() def error_calculation(event): global Items3 global Viewcanvas x = event.x + Offset_x y = event.y + Offset_y # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 Items3.append(6) # 复制一个图片,表示误差计算 new_item1 = Viewcanvas.create_image(x, y, image=List_image[6]) # 恢复图元的原位置 event.widget.coords(Dragged_item, Original_x, Original_y) # 将新图元的id和坐标添加到列表中 Items1.append((new_item1, x, y)) global x_loss global y_loss x_loss = x y_loss = y # 创建弹出窗口 top = creat_window('误差参数配置') # 创建一个下拉框,用于选择误差类型 loss_type_combobox=create_dropdown_box(top, '', ["CEE", "MSE", "MAE"]) # 创建 def get_input(): # 从下拉框中获取池化类型 loss_type = loss_type_combobox.get() # 复制对象的标签 Viewcanvas.create_text(x, y_loss + 40, text=str(loss_type) + "误差计算") if Listinstance[6][5] == ".": Listinstance[6][5] = str(loss_type) else: Listinstance[6][5] = Listinstance[6][5] + " " + str(loss_type) # 关闭窗口 top.destroy() button = tk.Button(top, text="获取信息", command=get_input) button.pack() def adjust_one(event): global Viewcanvas global Items1 global Items3 x = event.x + Offset_x y = event.y + Offset_y # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 Items3.append(7) # 复制一个图片,表示调整操作 new_item1 = Viewcanvas.create_image(x, y_loss - 20, image=List_image[7]) Viewcanvas.create_text(x, y_loss + 20, text='调整1')# 复制对象的标签 event.widget.coords(Dragged_item, Original_x, Original_y) # 恢复图元的原位置 Items1.append((new_item1, x, y))# 将新图元的id和坐标添加到列表中 def adjust_two(event): global Viewcanvas global Items1 global Items3 x = event.x + Offset_x y = event.y + Offset_y # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 Items3.append(8) # 复制一个图片,表示调整操作 new_item1 = Viewcanvas.create_image(x, y_loss + 20, image=List_image[7]) # 复制对象的标签 Viewcanvas.create_text(x, y_loss + 60, text='调整2') event.widget.coords(Dragged_item, Original_x, Original_y) # 恢复图元的原位置 # 将新图元的id和坐标添加到列表中 Items1.append((new_item1, x, y)) def adjust_three(event): global Viewcanvas global Items1 global Items3 x = event.x + Offset_x y = event.y + Offset_y # 记录被拖拽的原始图元的id,方便后续进行模型的正确性检查 Items3.append(9) # 复制一个图片,表示调整操作 new_item1 = Viewcanvas.create_image(x, y, image=List_image[7]) # 复制对象的标签 Viewcanvas.create_text(x, y + 40, text='调整3') event.widget.coords(Dragged_item, Original_x, Original_y) # 恢复图元的原位置 # 将新图元的id和坐标添加到列表中 Items1.append((new_item1, x, y)) def train_setting(): global Train_list Train_list = [] top = creat_window("训练参数配置")# 创建弹出的参数配置窗口 epoch_entry = create_input_box(top,"训练轮数:", 4)# 创建一个输入框,获取训练轮数 rate_entry=create_input_box(top, '学习率:', 0.1)# 创建一个输入框,获取学习率 batch_size_entry=create_input_box(top, "批次:", 60)# 创建一个输入框,获取批次 # 创建 def get_input(): # 获取输入框的内容 result1 = int(epoch_entry.get()) result2 = float(rate_entry.get()) result3 = int(batch_size_entry.get()) Train_list.append(result1) Train_list.append(result2) Train_list.append(result3) # 关闭窗口 top.destroy() button = tk.Button(top, text="获取信息", command=get_input) button.pack() def connecting_line(): global Viewcanvas global Items2 last_item = Items1[-1] # 获取最后一个图元的id和坐标 prev_item = Items1[-2] # 获取倒数第二个图元的id和坐标 # 获取最后一个图元的边界框坐标,形式为(x1,y1,x2,y2),其中(x1,y1)是左上角,(x2,y2)是右下角 last_bbox = Viewcanvas.bbox(last_item[0]) # 获取倒数第二个图元的边界框坐标,形式同上 prev_bbox = Viewcanvas.bbox(prev_item[0]) # 计算线条的起点和终点,使其与图元的边界对齐,并留出一定距离以避免重叠 start_x = prev_bbox[2] + 5 # 起点x坐标为倒数第二个图元右边界加10像素 start_y = prev_bbox[3] - (prev_bbox[3] - prev_bbox[1]) / 2 # 起点y坐标为倒数第二个图元垂直中心 end_x = last_bbox[0] # 终点x坐标为最后一个图元左边界 end_y = last_bbox[3] - (last_bbox[3] - last_bbox[1]) / 2 # 终点y坐标为最后一个图元垂直中心 # 创建一条线,带有箭头,并设置箭头形状、大小、颜色和平滑度等参数 if Items3[-1] < 6: new_item = Viewcanvas.create_line(start_x, start_y, end_x, end_y, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=True) if Items3[-1] == 1: x = last_bbox[2] - (last_bbox[2] - last_bbox[0]) / 2 y = last_bbox[1] Conv_xy_list.append((x, y)) if Items3[-1] == 3: x = last_bbox[2] - (last_bbox[2] - last_bbox[0]) / 2 y = last_bbox[1] Fullconn_xy_list.append((x, y)) elif Items3[-1] == 6: # 计算折线的中间点,使其与图元的边界对齐,并留出一定距离以避免重叠 mid_x = prev_bbox[2] - (prev_bbox[2] - prev_bbox[0]) / 2 # 中间点x坐标为起点和终点的平均值 mid_y = prev_bbox[1] - 80 # 中间点y坐标为起点y坐标减20像素 # 创建一条折线,带有箭头,并设置箭头形状、大小、颜色和平滑度等参数 x1 = prev_bbox[2] - (prev_bbox[2] - prev_bbox[0]) / 2 y1 = prev_bbox[1] x2 = last_bbox[2] y2 = last_bbox[3] - (last_bbox[3] - last_bbox[1]) / 2 new_item = Viewcanvas.create_line(x1, y1, mid_x, mid_y, x2, y2, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=False) elif Items3[-1] == 7: x1 = x_loss y1 = y_loss x2, y2 = Conv_xy_list[0] new_item = Viewcanvas.create_line(x1, y1, last_bbox[2] - (last_bbox[2] - last_bbox[0]) / 2, last_bbox[3] - (last_bbox[3] - last_bbox[1]) / 2, x2, y2, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=False) Conv_xy_list.remove(Conv_xy_list[0]) elif Items3[-1] == 8: x1 = x_loss y1 = y_loss x2, y2 = Fullconn_xy_list[0] new_item = Viewcanvas.create_line(x1, y1, last_bbox[2] - (last_bbox[2] - last_bbox[0]) / 2, last_bbox[3] - (last_bbox[3] - last_bbox[1]) / 2, x2, y2, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=False) Fullconn_xy_list.remove(Fullconn_xy_list[0]) Items2.append(new_item) def on_drag(obj_id1,event): while obj_id1 == 4: # 如果拖拽的是图元加载数据集 entity_loading_dataset(event) break while obj_id1 == 6: # 卷积 convolution(event) break while obj_id1 == 8: # 池化 pooling(event) break while obj_id1 == 10: # 全连接 fully_connected(event) break while obj_id1 == 12: # 非线性 nonlinear(event) break while obj_id1 == 14: # 分类 class_ification(event) break while obj_id1 == 16: # 误差计算 error_calculation(event) break while obj_id1 == 18: # 调整1 adjust_one(event) break while obj_id1 == 20: # 调整2 adjust_two(event) break while obj_id1 == 22: # 调整3 adjust_three(event) break # 定义图元拖拽结束的函数 def on_drag_end(event): obj_id1 = Dragged_item[0] # 获取被拖拽的图元的id # 使用 print(obj_id1) 从而查看各个图元的id,此步省略 # 根据图元的类型,复制相应的图片到右侧画布 on_drag(obj_id1,event) # 如果列表中有至少两个图元,就创建一条线,连接最后两个图元的中心点 while len(Items1) >= 2: connecting_line() break def element_binding(obj_x, obj_y, image, y, text): global Viewcanvas l1 = Viewcanvas.create_image(obj_x, obj_y, image=image) # 创建图元对象 # 创建图元对象的标签 Viewcanvas.create_text(obj_x - 70, obj_y + y, text=text, font=("黑体", 14)) return l1 def create_left_element(AllModelObj,List_image): global Viewcanvas # 遍历AllModelObj列表,在窗口左侧创建图元菜单 for obj in AllModelObj: # 获取图元对象的类型、标签等信息 obj_type = obj[1] # 并且要根据需求调整每个对象的位置 obj_x = obj[6] # 根据对象的id计算x坐标 obj_y = obj[7] # 根据对象的id计算y坐标 # 根据对象的类型,绘制相应的图形 if obj_type == 1: # 加载数据集 l1 = element_binding(obj_x, obj_y, List_image[0], 3, " 加载" + "\n" + "数据集") elif obj_type == 2: # 卷积 l1 = element_binding(obj_x, obj_y, List_image[1], 0, "卷积") elif obj_type == 3: # 池化 l1 = element_binding(obj_x, obj_y, List_image[2], 0, "池化") elif obj_type == 4: # 全连接 l1 = element_binding(obj_x, obj_y, List_image[3], 0, "全连接" + "\n" + " 函数") elif obj_type == 5: # 非线性 l1 = element_binding(obj_x, obj_y, List_image[4], 0, "非线性" + "\n" + " 函数") elif obj_type == 6: # 分类 l1 = element_binding(obj_x, obj_y, List_image[5], 0, "类别") elif obj_type == 7: # 误差计算 l1 = element_binding(obj_x, obj_y, List_image[6], 0, "误差") elif obj_type == 8: # 调整 l1 = element_binding(obj_x, obj_y, List_image[7], 0, "调整1") elif obj_type == 9: # 调整 l1 = element_binding(obj_x, obj_y, List_image[7], 0, "调整2") elif obj_type == 10: # 调整 l1 = element_binding(obj_x, obj_y, List_image[7], 0, "调整3") elif obj_type == 11: # 调整 l1 = element_binding(obj_x, obj_y, List_image[8], 3, "主数据连接线") elif obj_type == 12: # 调整 l1 = element_binding(obj_x, obj_y, List_image[9], 3, "参数连接线") # 为左边菜单的每个图元绑定鼠标按下、移动和松开的事件 Viewcanvas.tag_bind(l1, "", on_drag_start) Viewcanvas.tag_bind(l1, "", on_drag_motion) Viewcanvas.tag_bind(l1, "", on_drag_end) # if __name__ == '__main__': # Root = tk.Tk() # # 设置窗口的大小为1200*750 # window_width = 1200 # 窗口的宽度 # window_height = 750 # 窗口的高度 # Root.title("神经网络可视化") # Root.geometry("1200x750") # 设置窗口的大小和位置 # picture_frame(window_width,window_height) # Listinstance = create_instance() # listclass = connect_class(Listinstance) # # 创建网络对象总表和网络连接对象总表 # AllModelObj = [Listinstance[0], Listinstance[1], Listinstance[2], Listinstance[3], Listinstance[4], Listinstance[5], # Listinstance[6], Listinstance[7], Listinstance[8], Listinstance[9]] # AllModelConn = [listclass[0], listclass[1], listclass[2], listclass[3], listclass[4], listclass[5], listclass[6], # listclass[7], listclass[8], listclass[9]] # img_path = ["img/data.png", "img/conv.png", "img/pool.png", "img/full_connect.png", "img/nonlinear.png", # "img/classifier.png", "img/error.png", "img/adjust.png", "img/arrow1.png", "img/arrow2.png"] # List_image = [] # for path in img_path: # List_image.append(element(path)) # create_left_element(AllModelObj, List_image) # button = push_button() # Root.mainloop() # if __name__ == '__main__': # Root = tk.Tk() # train_setting() # Root.mainloop() def check_connection(): connection = [x for x in Items3 if x < 6] length = len(connection) if length == 0: messagebox.showerror("错误", "请添加图元!") return for i in range(length-1): right_model_x = connection[i] right_model_y = connection[i+1] if RIGHT_MODEL[right_model_x][right_model_y] == 0: messagebox.showerror("错误", "连接不正确,请检查!") return messagebox.showinfo("成功", "连接正确,恭喜!") def number_judgments(lsts): global Items3 count = [] sequence = [] for index,lll in enumerate(lsts): if type(lll) == list: count.append(lll[1]) sequence.append(index) if lll[1]==9: break count_2,count_3,count_4=0,0,0 list_count=[] for i in count: if i == 2: count_2 += 1 list_count.append(i*10+count_2) elif i == 3: count_3 += 1 list_count.append(i * 10 + count_3) elif i == 4: count_4 += 1 list_count.append(i * 10 + count_4) else: list_count.append(i * 10) Items3 = [0] for i in count: Items3.append(i - 1) return count,list_count,sequence def load_file(): filename = filedialog.askopenfilename(filetypes=[("Pickle files", "*.pkl")]) # 从本地文件中读取两个列表,用rb模式打开文件 with open(filename, "rb") as f: # 创建一个空列表,用来存储读取的列表 lsts = [] # 用一个循环来读取所有的列表,直到文件结束 while True: try: # 读取一个列表,并追加到大列表中 lst = pickle.load(f) lsts.append(lst) except EOFError: # 如果遇到文件结束的错误,就跳出循环 break return lsts def connecting_lines(obj_x, obj_y, index, x, y, x1, x2, y1, y2, y3 , image, text, smooth, width): # 创建图元对象 Viewcanvas.create_image(obj_x+(index + x) * 110, obj_y, image=image) # 创建图元对象的标签 Viewcanvas.create_text(obj_x+(index + x) * 110, obj_y + y1, text=text, font=("黑体", 14)) # 创建数据线箭头 Viewcanvas.create_line(obj_x+(index + x) * 110 + x1, obj_y + y2, obj_x+(index + y) * 110 + x2, obj_y + y3, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth, width=1) def connecting(obj_x, obj_y, index, x, y1, image, text): # 创建图元对象 Viewcanvas.create_image(obj_x+(index + x) * 110, obj_y, image=image) # 创建图元对象的标签 Viewcanvas.create_text(obj_x+(index + x) * 110, obj_y + y1, text=text, font=("黑体", 14)) # 加载已有模型 def load_model(): import copy global Train_images global Test_images global Viewcanvas global Listinstance global Viewcanvas lsts = load_file() DataPara = setload_data() create_left_element(AllModelObj, List_image) Train_images, Test_images = load_data(DataPara) # load_data()函数,根据参数加载数据集 # 打印一些信息,检查是否正确加载 print("训练集图片的形状:", Train_images.shape) print("测试集图片的形状:", Test_images.shape) # 根据pkl文件的前向传播顺序列表,依次识别卷积层、池化层、全连接层、非线性层和分类层的操作 count,counts,sequence = number_judgments(lsts) x,y = 420,300 connecting_lines(x, y, 0, 0, 0, 25, 60, 45, 0, 0, List_image[0], '数据集', True, 3) for layer in range(len(count)): if count[layer] == 2: # 如果是卷积层,将读取的卷积层的信息存储到Conv实例 if counts[layer]%10 == 1: global Conv1 Listinstance[1] = copy.deepcopy(lsts[sequence[layer]]) Conv1 = lsts[sequence[layer]] connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层1', True, 3) if counts[layer]%10 == 2: global Conv2 Conv2 = lsts[sequence[layer]] connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层2', True, 3) if counts[layer]%10 == 3: global Conv3 Conv3 = lsts[sequence[layer]] connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层3', True, 3) if count[layer] == 3: # 如果是池化层,将读取的池化层的信息存储到Pool实例 if counts[layer]%10 == 1: global Pool1 Listinstance[2] =copy.deepcopy(lsts[sequence[layer]]) Pool1 = lsts[sequence[layer]] connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化1', True, 3) if counts[layer]%10 == 2: global Pool2 Pool2 = lsts[sequence[layer]] connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化2', True, 3) if counts[layer]%10 == 3: global Pool3 Pool3 = lsts[sequence[layer]] connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化3', True, 3) if count[layer] == 4: # 如果是全连接层,将读取的全连接层的信息存储到Pool实例 if counts[layer]%10 == 1: global Fullconn1 Listinstance[3] = lsts[sequence[layer]] Fullconn1 = copy.deepcopy(lsts[sequence[layer]])# 深拷贝创建了一个全新的对象,要使用深拷贝,不然报错 Listinstance[3][5] = str(Fullconn1[5][1]["num_outputs"]) connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[3], '全连接1', True, 3) if counts[layer]%10 == 2: global Fullconn2 Fullconn2 = lsts[sequence[layer]] # FullConn[5] = FullConn[5] + " " + str(Fullconn2[5][2]["num_outputs"]) connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[3], '全连接3', True, 3) if counts[layer]%10 == 3: global Fullconn3 Fullconn3 = lsts[sequence[layer]] # FullConn[5] = FullConn[5] + " " + str(Fullconn3[5][3]["num_outputs"]) connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[3], '全连接3', True, 3) if count[layer] == 5: # 如果是非线性层,将读取的非线性层的信息存储到Nonline实例 Listinstance[4] = lsts[sequence[layer]] connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[4], '非线性', True, 3) if count[layer] == 6: # 如果是分类输出层,将读取的信息存储到Nonline实例 Listinstance[5] = lsts[sequence[layer]] connecting(x, y, layer, 1, 45,List_image[5], '分类') if count[layer] == 7: # 如果是计算误差层,将读取的信息存储到Error实例 Listinstance[6] = lsts[sequence[layer]] connecting(x-30, y-120, layer, 0, 45, List_image[6], '计算误差') Viewcanvas.create_line(x + layer * 110 + 25, y, x + layer * 110 + 10, y - 60, x + 5 * 110 - 20, y - 120, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=True, width=2) # 创建图元对象 Viewcanvas.create_image(600, 180, image=List_image[7]) # 创建图元对象的标签 Viewcanvas.create_text(600, 230, text='调整1', font=("黑体", 14)) Viewcanvas.create_line(x + layer * 110 - 50, y - 140, 630, 165, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=True, width=2) Viewcanvas.create_line(600, 200, x + 1 * 110, y - 20, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=True, width=2) # 创建图元对象 Viewcanvas.create_image(860, 200, image=List_image[7]) # 创建图元对象的标签 Viewcanvas.create_text(860, 250, text='调整2', font=("黑体", 14)) Viewcanvas.create_line(x + layer * 110 - 60, y - 120, 875, 200, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=True, width=2) Viewcanvas.create_line(835, 200, x + (layer - 2) * 110 + 10, y - 20, arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=True, width=2) def create_window(number,count,list1,list2,list3,list4,list5,list6): global Listinstance if number == 1: # 把数字的出现次数加一 count[number] = count.get(number, 0) + 1 if count[number] == 1: # 获取第一层卷积层的参数 para_list = list1[count[number] - 1].split(",") para_list = [int(x) for x in para_list] window = creat_window('卷积1参数调整') # 创建一个新的窗口 kernel_size_entry = create_input_box(window, "卷积核大小:", para_list[0]) # 创建一个输入框,获取卷积核大小 stride_entry = create_input_box(window, "卷积步长:", para_list[1]) # 创建一个输入框,获取卷积步 def modify_para(): # 获取输入框的内容 result1 = int(kernel_size_entry.get()) result2 = int(stride_entry.get()) new_para = str(result1)+ ','+str(result2) Listinstance[1][5] = Listinstance[1][5].replace(list1[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="卷积参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() if count[number] == 2: # 获取第一层卷积层的参数 para_list = list1[count[number] - 1].split(",") para_list = [int(x) for x in para_list] window = creat_window('卷积2参数调整') # 创建一个新的窗口 kernel_size_entry = create_input_box(window, "卷积核大小:", para_list[0]) # 创建一个输入框,获取卷积核大小 stride_entry = create_input_box(window, "卷积步长:", para_list[1]) # 创建一个输入框,获取卷积步 def modify_para(): # 获取输入框的内容 result1 = int(kernel_size_entry.get()) result2 = int(stride_entry.get()) new_para = str(result1)+ ','+str(result2) Listinstance[1][5] = Listinstance[1][5].replace(list1[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="卷积参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() if count[number] == 3: # 获取第一层卷积层的参数 para_list = list1[count[number] - 1].split(",") para_list = [int(x) for x in para_list] # 创建一个输入框,获取卷积核大小 window = creat_window('卷积3参数调整') # 创建一个新的窗口 kernel_size_entry = create_input_box(window, "卷积核大小:", para_list[0]) # 创建一个输入框,获取卷积核大小 stride_entry = create_input_box(window, "卷积步长:", para_list[1]) # 创建一个输入框,获取卷积步 def modify_para(): # 获取输入框的内容 result1 = int(kernel_size_entry.get()) result2 = int(stride_entry.get()) new_para = str(result1)+ ','+str(result2) Listinstance[1][5] = Listinstance[1][5].replace(list1[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="卷积参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() # 返回窗口对象 return window # 如果是池化层 if number == 2: # 把数字的出现次数加一 count[number] = count.get(number, 0) + 1 if count[number] == 1: # 获取第一层卷积层的参数 para_list = list2[count[number] - 1].split(",") para_list[1] = int(para_list[1]) window = creat_window('池化1参数调整') # 创建一个新的窗口 pool_type_combobox = create_dropdown_box(window, "池化池类型:", ["max", "avg", "min"]) # 创建一个下拉框,用于选择池化类型 pool_size_entry = create_input_box(window, "池化池大小:", para_list[1]) # 创建一个输入框,获取卷积步 def modify_para(): # 从下拉框中获取池化类型 pool_type = pool_type_combobox.get() # 从输入框中获取池大小 pool_size = int(pool_size_entry.get()) # 关闭窗口 new_para = str(pool_type)+ ','+str(pool_size) Listinstance[2][5] = Listinstance[2][5].replace(list2[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="池化参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() if count[number] == 2: # 获取第一层卷积层的参数 para_list = list2[count[number] - 1].split(",") para_list[1] = int(para_list[1]) window = creat_window('池化2参数调整') # 创建一个新的窗口 pool_type_combobox = create_dropdown_box(window, "池化池类型:", ["max", "avg", "min"]) # 创建一个下拉框,用于选择池化类型 pool_size_entry = create_input_box(window, "池化池大小:", para_list[1]) # 创建一个输入框,获取卷积步 def modify_para(): # 从下拉框中获取池化类型 pool_type = pool_type_combobox.get() # 从输入框中获取池大小 pool_size = int(pool_size_entry.get()) # 关闭窗口 new_para = str(pool_type)+ ','+str(pool_size) Listinstance[2][5] = Listinstance[2][5].replace(list2[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="池化参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() if count[number] == 3: # 获取第一层卷积层的参数 para_list = list2[count[number] - 1].split(",") para_list[1] = int(para_list[1]) window = creat_window('池化3参数调整') # 创建一个新的窗口 pool_type_combobox = create_dropdown_box(window, "池化池类型:", ["max", "avg", "min"]) # 创建一个下拉框,用于选择池化类型 pool_size_entry = create_input_box(window, "池化池大小:", para_list[1]) # 创建一个输入框,获取卷积步 def modify_para(): # 从下拉框中获取池化类型 pool_type = pool_type_combobox.get() # 从输入框中获取池大小 pool_size = int(pool_size_entry.get()) # 关闭窗口 new_para = str(pool_type)+ ','+str(pool_size) Listinstance[2][5] = Listinstance[2][5].replace(list2[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="池化参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() # 返回窗口对象 return window if number == 3: # 把数字的出现次数加一 count[number] = count.get(number, 0) + 1 if count[number] == 1: # 获取第一层全连接层的参数 para = list3[count[number] - 1] para = int(para) window = creat_window('全连接1参数调整') # 创建一个新的窗口 num_outputs_entry = create_input_box(window, "输出维度:", para) # 创建一个输入框,获取卷积步 def modify_para(): # 获取输入框的内容 num = int(num_outputs_entry.get()) new_para = str(num) Listinstance[3][5] = Listinstance[3][5].replace(list3[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="全连接参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() if count[number] == 2: # 获取第一层全连接层的参数 para = list3[count[number] - 1] para = int(para) window = creat_window('全连接2参数调整') # 创建一个新的窗口 num_outputs_entry = create_input_box(window, "输出维度:", para) # 创建一个输入框,获取全连接 def modify_para(): # 获取输入框的内容 num = int(num_outputs_entry.get()) new_para = str(num) Listinstance[3][5] = Listinstance[3][5].replace(list3[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="全连接参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() if count[number] == 3: # 获取第一层全连接层的参数 para = list3[count[number] - 1] para = int(para) window = creat_window('全连接3参数调整') # 创建一个新的窗口 num_outputs_entry = create_input_box(window, "输出维度:", para) # 创建一个输入框,获取全连接 def modify_para(): # 获取输入框的内容 num = int(num_outputs_entry.get()) new_para = str(num) Listinstance[3][5] = Listinstance[3][5].replace(list3[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="全连接参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() # 返回窗口对象 return window if number == 4: # 把数字的出现次数加一 count[number] = count.get(number, 0) + 1 if count[number] == 1: # 获取第一层非线性层的参数 para = list3[count[number] - 1] window = creat_window('非线性1参数调整') # 创建一个新的窗口 nonlinear_mode_combobox = create_dropdown_box(window, "非线性类型:", ["Sigmoid", "ReLU", "Tanh"]) # 创建一个下拉框,用于选择非线性类型 def modify_para(): # 获取输入框的内容 nonlinear_mode = nonlinear_mode_combobox.get() new_para = f"{nonlinear_mode}" Listinstance[4][5] = Listinstance[4][5].replace(list4[count[number] - 1], new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="非线性参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() # 返回窗口对象 return window if number == 5: # 把数字的出现次数加一 count[number] = count.get(number, 0) + 1 if count[number] == 1: # 获取分类的参数 para = list5 para = float(para) window = creat_window('分类参数调整') # 创建一个新的窗口 threshold_entry = create_input_box(window, "阈值:", para) # 创建一个输入框,用于输入阈值 def modify_para(): # 获取输入框的内容 threshold = threshold_entry.get() new_para = str(threshold) Listinstance[5][5] = Listinstance[5][5].replace(list5, new_para) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="分类参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() # 返回窗口对象 return window if number == 6: # 把数字的出现次数加一 count[number] = count.get(number, 0) + 1 if count[number] == 1: # 获取分类的参数 para = list6 window = creat_window('误差参数调整') # 创建一个新的窗口 loss_type_combobox = create_dropdown_box(window, "误差类型:", ["CEE", "MSE", "MAE"]) # 创建一个下拉框,用于选择误差类型 def modify_para(): # 获取输入框的内容 loss_type = loss_type_combobox.get() new_para = str(loss_type) Listinstance[6][5] = Listinstance[6][5].replace(list6[count[number] - 1], new_para) print(Listinstance[6]) # 关闭窗口 window.destroy() # 创建一个按钮,文本为数字 button = tk.Button(window, text="误差参数修改") # 绑定按钮的点击事件,使得点击后销毁窗口 button.config(command=modify_para) # 把按钮放在窗口中 button.pack() return window # 返回窗口对象 # 清空当前模型展示区 def restart_new_model(): # 这将在子进程中调用当前Python解释器,并传递当前文件的路径作为参数 subprocess.call([sys.executable, __file__]) def setpara_func(): # 图元参数配置与修改 global Viewcanvas # 一个字典,用来记录每个数字出现的次数 count = {} list1 = Listinstance[1][5].split() list2 = Listinstance[2][5].split() list3 = Listinstance[3][5].split() list4 = Listinstance[4][5].split() list5 = Listinstance[5][5] list6 = Listinstance[6][5].split() for i in Items4: # 清除所有文字标签 Viewcanvas.delete(i[0]) numbers = [x for x in Items3 if x <= 6] # 一个函数,用来创建一个带有一个数字标签的按钮的窗口 numbers = numbers[1:] def iterate_numbers(): # 一个函数,用来遍历数字列表,依次创建窗口 if numbers: # 如果数字列表不为空 number = numbers.pop(0) # 从列表中弹出第一个数字 window = create_window(number, count, list1, list2, list3, list4, list5, list6) window.wait_window() # 等待窗口被关闭 iterate_numbers() # 再次调用这个函数,创建下一个窗口 iterate_numbers() # 调用遍历数字的函数 def redirector(inputStr): global Text Text.configure(state="normal") # 设置文本框为可编辑状态 Text.insert("end", inputStr) # 在文本框末尾插入内容 Text.see("end") # 滚动到末尾 Text.configure(state="disabled") # 设置文本框为只读状态 def close_program(): sys.exit() if __name__ == '__main__': # 创建一个主窗口 Root = tk.Tk() # 设置窗口的大小为1200*750 window_width = 1200 # 窗口的宽度 window_height = 750 # 窗口的高度 Root.title("神经网络可视化") Root.geometry("1200x750") # 设置窗口的大小和位置 picture_frame(window_width,window_height) Listinstance = create_instance() listclass = connect_class(Listinstance) # 创建网络对象总表和网络连接对象总表 AllModelObj = [Listinstance[0], Listinstance[1], Listinstance[2], Listinstance[3], Listinstance[4], Listinstance[5], Listinstance[6], Listinstance[7], Listinstance[8], Listinstance[9]] AllModelConn = [listclass[0], listclass[1], listclass[2], listclass[3], listclass[4], listclass[5], listclass[6], listclass[7], listclass[8], listclass[9]] img_path = ["img/data.png", "img/conv.png", "img/pool.png", "img/full_connect.png", "img/nonlinear.png", "img/classifier.png", "img/error.png", "img/adjust.png", "img/arrow1.png", "img/arrow2.png"] List_image = [] for path in img_path: List_image.append(element(path)) create_left_element(AllModelObj, List_image) button = push_button() button['button1'].config(command=train_setting) button['button4'].config(command=load_model) button['button5'].config(command=restart_new_model) button['button6'].config(command=setpara_func) button['button8'].config(command=check_connection) button['button9'].config(command=close_program) sys.stdout.write = redirector Root.mainloop()