|
|
|
|
import sys
|
|
|
|
|
import pickle
|
|
|
|
|
import subprocess
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from tkinter import ttk
|
|
|
|
|
from tkinter import messagebox
|
|
|
|
|
import tkinter.scrolledtext as st
|
|
|
|
|
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", ".", 90, 40).output()
|
|
|
|
|
Conv = ModelObj("Conv", 2, "卷积", "ConvProc", "SetConvPara", ".", 200, 40).output()
|
|
|
|
|
Pool = ModelObj("Pool", 3, "最大池化", "MaxPoolProc", "SetPollPara", ".", 90, 105).output()
|
|
|
|
|
FullConn = ModelObj("FullConn", 4, "全连接", "FullConnProc", "SetFullConnPara", ".", 200, 105).output()
|
|
|
|
|
Nonline = ModelObj("Nonline", 5, "非线性函数", "NonlinearProc", "SetNonLPara", ".", 90, 170).output()
|
|
|
|
|
Classifier = ModelObj("Classifier", 6, "分类", "ClassifierProc", "SetClassifyPara", ".", 200, 170).output()
|
|
|
|
|
Error = ModelObj("Error", 7, "误差计算", "ErrorProc", "SetErrorPara", ".", 90, 235).output()
|
|
|
|
|
AjConv = ModelObj("AjConv", 8, "卷积调整", "AjConvProc", "SetAjConvPara", ".", 200, 235).output()
|
|
|
|
|
AjFullconn = ModelObj("AjFullconn", 9, "全连接调整", "AjFullconnProc", "SetAjFCPara", ".", 90, 300).output()
|
|
|
|
|
AjNonline = ModelObj("AjNonline", 10, "非线性调整", "AjNonlineProc", "SetAjNLPara", ".", 200, 300).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-30 # 第一个矩形框的宽度
|
|
|
|
|
rect1_height = window_height * 3 / 4 - gap * 2 # 第一个矩形框的高度
|
|
|
|
|
rect2_x = window_width * 1 / 3 + gap - 30 # 第二个矩形框的左上角x坐标
|
|
|
|
|
rect2_y = gap # 第二个矩形框的左上角y坐标
|
|
|
|
|
rect2_width = window_width * 2 / 3 - gap + 30 # 第二个矩形框的宽度
|
|
|
|
|
rect2_height = window_height * 3 / 4 - gap * 2 # 第二个矩形框的高度
|
|
|
|
|
rect3_x = gap # 第三个矩形框的左上角x坐标
|
|
|
|
|
rect3_y = window_height * 3 / 4 + gap # 第三个矩形框的左上角y坐标
|
|
|
|
|
rect3_width = window_width - gap * 2 # 第三个矩形框的宽度
|
|
|
|
|
rect3_height = window_height * 1 / 4 - gap * 2 # 第三个矩形框的高度
|
|
|
|
|
global Viewcanvas
|
|
|
|
|
# 创建一个画布,用于绘制矩形框,设置画布的大小和背景色
|
|
|
|
|
Viewcanvas = tk.Canvas(Root, width=window_width, height=window_height, bg="white")
|
|
|
|
|
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=760, 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((40, 30))
|
|
|
|
|
# 把Image对象转换成PhotoImage对象
|
|
|
|
|
img = ImageTk.PhotoImage(img)
|
|
|
|
|
# 保存图片的引用,防止被垃圾回收
|
|
|
|
|
Root.img = img
|
|
|
|
|
return img
|
|
|
|
|
|
|
|
|
|
def push_button():
|
|
|
|
|
button = {}
|
|
|
|
|
style = ttk.Style(Root)
|
|
|
|
|
# 设置blue.TButton样式的背景色为亮蓝灰,前景色为白色
|
|
|
|
|
style.configure("blue.TButton", background="LightSlateGray", foreground="black", font=("黑体", 10))
|
|
|
|
|
style.map("blue.TButton",
|
|
|
|
|
background=[('active', 'PowderBlue'), ('pressed', 'red')], # 设置激活状态下的背景色为粉蓝色,按下状态下的背景色为红色
|
|
|
|
|
foreground=[('active', 'black'), ('pressed', 'white')]) # 设置激活状态下的前景色为黑色,按下状态下的前景色为白色
|
|
|
|
|
# 设置green.TButton样式的背景色为中海洋绿,前景色为白色
|
|
|
|
|
style.configure("green.TButton", background="MediumSeaGreen", foreground="black", font=("黑体", 8))
|
|
|
|
|
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=330)
|
|
|
|
|
button['button1'] = button1
|
|
|
|
|
button2 = ttk.Button(Root, text=" 训练 ", style="blue.TButton")
|
|
|
|
|
button2.place(x=140, y=330)
|
|
|
|
|
button['button2'] = button2
|
|
|
|
|
button3 = ttk.Button(Root, text=" 输出模型程序 ", style="blue.TButton")
|
|
|
|
|
button3.place(x=240, y=330)
|
|
|
|
|
button['button3'] = button3
|
|
|
|
|
# 创建五个按钮,用于触发操作
|
|
|
|
|
button4 = ttk.Button(Root, text=" 加载已有模型 ", style="green.TButton")
|
|
|
|
|
button4.place(x=255, y=10)
|
|
|
|
|
button['button4'] = button4
|
|
|
|
|
button5 = ttk.Button(Root, text=" 新建模型 ", style="green.TButton")
|
|
|
|
|
button5.place(x=355, y=10)
|
|
|
|
|
button['button5'] = button5
|
|
|
|
|
button6 = ttk.Button(Root, text=" 图元参数设置 ", style="green.TButton")
|
|
|
|
|
button6.place(x=435, y=10)
|
|
|
|
|
button['button6'] = button6
|
|
|
|
|
button7 = ttk.Button(Root, text=" 保存模型 ", style="green.TButton")
|
|
|
|
|
button7.place(x=535, y=10)
|
|
|
|
|
button['button7'] = button7
|
|
|
|
|
button8 = ttk.Button(Root, text=" 模型正确性检查 ", style="green.TButton")
|
|
|
|
|
button8.place(x=615, y=10)
|
|
|
|
|
button['button8'] = button8
|
|
|
|
|
button9 = ttk.Button(Root, text="退出", style="green.TButton")
|
|
|
|
|
button9.place(x=725, y=10)
|
|
|
|
|
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 = tk.Toplevel(Root) # 创建弹出窗口
|
|
|
|
|
top.geometry("300x250")
|
|
|
|
|
top.title("全连接参数配置")
|
|
|
|
|
num_outputs_entry = create_input_box(top, "全连接输出维度:", 10)
|
|
|
|
|
# 创建
|
|
|
|
|
def get_input():
|
|
|
|
|
global Listinstance
|
|
|
|
|
# 从下拉框中获取输出维度
|
|
|
|
|
num = int(num_outputs_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 = tk.Toplevel(Root) # 创建弹出窗口
|
|
|
|
|
top.geometry("300x250")
|
|
|
|
|
top.title("分类参数配置")
|
|
|
|
|
# 创建一个输入框,用于输入阈值
|
|
|
|
|
threshold_label = tk.Label(top, text="阈值:")
|
|
|
|
|
threshold_label.pack(padx=10, pady=10)
|
|
|
|
|
threshold = tk.DoubleVar(top, value=0.001) # 创建一个DoubleVar对象,并设置默认值为0.001
|
|
|
|
|
threshold_entry = tk.Entry(top, textvariable=threshold) # 关联DoubleVar对象
|
|
|
|
|
threshold_entry.pack(padx=20, pady=20)
|
|
|
|
|
|
|
|
|
|
# 创建
|
|
|
|
|
def get_input():
|
|
|
|
|
# 从输入框中获取阈值
|
|
|
|
|
threshold = float(threshold_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 - 40, obj_y + y, text=text, font=("黑体", 10))
|
|
|
|
|
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, "<Button-1>", on_drag_start)
|
|
|
|
|
Viewcanvas.tag_bind(l1, "<B1-Motion>", on_drag_motion)
|
|
|
|
|
Viewcanvas.tag_bind(l1, "<ButtonRelease-1>", 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]==7:
|
|
|
|
|
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) * 80, obj_y, image=image)
|
|
|
|
|
# 创建图元对象的标签
|
|
|
|
|
Viewcanvas.create_text(obj_x+(index + x) * 80, obj_y + y1, text=text, font=("黑体", 8))
|
|
|
|
|
# 创建数据线箭头
|
|
|
|
|
Viewcanvas.create_line(obj_x+(index + x) * 80 + x1, obj_y + y2, obj_x+(index + y) * 80 + 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) * 80, obj_y, image=image)
|
|
|
|
|
# 创建图元对象的标签
|
|
|
|
|
Viewcanvas.create_text(obj_x+(index + x) * 80, obj_y + y1, text=text, font=("黑体", 8))
|
|
|
|
|
# 加载已有模型
|
|
|
|
|
def load_model():
|
|
|
|
|
import copy
|
|
|
|
|
global Train_images
|
|
|
|
|
global Test_images
|
|
|
|
|
global Viewcanvas
|
|
|
|
|
global Listinstance
|
|
|
|
|
global Viewcanvas
|
|
|
|
|
lsts = load_file()
|
|
|
|
|
DataPara = setload_data()
|
|
|
|
|
Viewcanvas.delete('all')
|
|
|
|
|
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 = 290,200
|
|
|
|
|
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 + 5 * 80 + 25, y, x + 5 * 80 + 20, y - 80,
|
|
|
|
|
x + 5 * 80 -20 , y-120, arrow=tk.LAST, arrowshape=(16, 20, 4),
|
|
|
|
|
fill='lightblue', smooth=True, width=1)
|
|
|
|
|
|
|
|
|
|
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 = 800 # 窗口的宽度
|
|
|
|
|
window_height = 450 # 窗口的高度
|
|
|
|
|
Root.title("神经网络可视化")
|
|
|
|
|
Root.geometry("800x450") # 设置窗口的大小和位置
|
|
|
|
|
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()
|