|
|
@ -7,14 +7,12 @@ import functools
|
|
|
|
import numpy as np
|
|
|
|
import numpy as np
|
|
|
|
import pandas as pd
|
|
|
|
import pandas as pd
|
|
|
|
import tkinter as tk
|
|
|
|
import tkinter as tk
|
|
|
|
import ttkbootstrap as ttk
|
|
|
|
from tkinter import ttk
|
|
|
|
from tkinter import messagebox
|
|
|
|
from tkinter import messagebox
|
|
|
|
import tkinter.scrolledtext as st
|
|
|
|
import tkinter.scrolledtext as st
|
|
|
|
from PIL import Image, ImageTk
|
|
|
|
from PIL import Image, ImageTk
|
|
|
|
from ttkbootstrap import *
|
|
|
|
|
|
|
|
from tkinter import Canvas, Frame, BOTH, PhotoImage, filedialog
|
|
|
|
from tkinter import Canvas, Frame, BOTH, PhotoImage, filedialog
|
|
|
|
from X4 import setload_data
|
|
|
|
from X3 import setload_data,load_data
|
|
|
|
from X3 import load_data
|
|
|
|
|
|
|
|
from X2 import ModelObj
|
|
|
|
from X2 import ModelObj
|
|
|
|
# 网络模型正确的图元和连接关系的数据结构,用一个字典表示
|
|
|
|
# 网络模型正确的图元和连接关系的数据结构,用一个字典表示
|
|
|
|
RIGHT_MODEL = [
|
|
|
|
RIGHT_MODEL = [
|
|
|
@ -55,6 +53,7 @@ Items3 = [] # 存储被拖拽的图元的列表
|
|
|
|
Items4 = [] # 存储新图元文字标签的列表
|
|
|
|
Items4 = [] # 存储新图元文字标签的列表
|
|
|
|
Counts = {} # 用来存储Items3每个数字出现过的次数
|
|
|
|
Counts = {} # 用来存储Items3每个数字出现过的次数
|
|
|
|
Conv_xy_list = [] # 存储卷积图元的坐标
|
|
|
|
Conv_xy_list = [] # 存储卷积图元的坐标
|
|
|
|
|
|
|
|
Pool_xy_list = [] # 存储全连接图元的坐标
|
|
|
|
Fullconn_xy_list = [] # 存储全连接图元的坐标
|
|
|
|
Fullconn_xy_list = [] # 存储全连接图元的坐标
|
|
|
|
Train_list = [] # 存储训练设置参数
|
|
|
|
Train_list = [] # 存储训练设置参数
|
|
|
|
Listinstance = [] # 图元对象实例
|
|
|
|
Listinstance = [] # 图元对象实例
|
|
|
@ -68,16 +67,16 @@ Batch = 0 #批次
|
|
|
|
|
|
|
|
|
|
|
|
def create_instance():
|
|
|
|
def create_instance():
|
|
|
|
# 创建图元对象实例
|
|
|
|
# 创建图元对象实例
|
|
|
|
DataSet = ModelObj("DataSet", 1, "数据集", "LoadData", "SetDataPara", ".", 120, 70).output()
|
|
|
|
DataSet = ModelObj("DataSet", 1, "数据集", "LoadData", "SetDataPara", ".", 90, 40).output()
|
|
|
|
Conv = ModelObj("Conv", 2, "卷积", "ConvProc", "SetConvPara", ".", 280, 70).output()
|
|
|
|
Conv = ModelObj("Conv", 2, "卷积", "ConvProc", "SetConvPara", ".", 200, 40).output()
|
|
|
|
Pool = ModelObj("Pool", 3, "最大池化", "MaxPoolProc", "SetPollPara", ".", 120, 165).output()
|
|
|
|
Pool = ModelObj("Pool", 3, "最大池化", "MaxPoolProc", "SetPollPara", ".", 90, 105).output()
|
|
|
|
FullConn = ModelObj("FullConn", 4, "全连接", "FullConnProc", "SetFullConnPara", ".", 280, 165).output()
|
|
|
|
FullConn = ModelObj("FullConn", 4, "全连接", "FullConnProc", "SetFullConnPara", ".", 200, 105).output()
|
|
|
|
Nonline = ModelObj("Nonline", 5, "非线性函数", "NonlinearProc", "SetNonLPara", ".", 120, 260).output()
|
|
|
|
Nonline = ModelObj("Nonline", 5, "非线性函数", "NonlinearProc", "SetNonLPara", ".", 90, 170).output()
|
|
|
|
Classifier = ModelObj("Classifier", 6, "分类", "ClassifierProc", "SetClassifyPara", ".", 280, 260).output()
|
|
|
|
Classifier = ModelObj("Classifier", 6, "分类", "ClassifierProc", "SetClassifyPara", ".", 200, 170).output()
|
|
|
|
Error = ModelObj("Error", 7, "误差计算", "ErrorProc", "SetErrorPara", ".", 120, 355).output()
|
|
|
|
Error = ModelObj("Error", 7, "误差计算", "ErrorProc", "SetErrorPara", ".", 90, 235).output()
|
|
|
|
AjConv = ModelObj("AjConv", 8, "卷积调整", "AjConvProc", "SetAjConvPara", ".", 280, 355).output()
|
|
|
|
AjConv = ModelObj("AjConv", 8, "卷积调整", "AjConvProc", "SetAjConvPara", ".", 200, 235).output()
|
|
|
|
AjFullconn = ModelObj("AjFullconn", 9, "全连接调整", "AjFullconnProc", "SetAjFCPara", ".", 120, 450).output()
|
|
|
|
AjFullconn = ModelObj("AjFullconn", 9, "全连接调整", "AjFullconnProc", "SetAjFCPara", ".", 90, 300).output()
|
|
|
|
AjNonline = ModelObj("AjNonline", 10, "非线性调整", "AjNonlineProc", "SetAjNLPara", ".", 280, 450).output()
|
|
|
|
AjNonline = ModelObj("AjNonline", 10, "非线性调整", "AjNonlineProc", "SetAjNLPara", ".", 200, 300).output()
|
|
|
|
listinstance = [DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn, AjNonline]
|
|
|
|
listinstance = [DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn, AjNonline]
|
|
|
|
return listinstance # 还回图元对象实例列表
|
|
|
|
return listinstance # 还回图元对象实例列表
|
|
|
|
|
|
|
|
|
|
|
@ -86,30 +85,30 @@ def picture_frame(window_width,window_height):
|
|
|
|
# 计算矩形框的坐标和尺寸
|
|
|
|
# 计算矩形框的坐标和尺寸
|
|
|
|
rect1_x = gap # 第一个矩形框的左上角x坐标
|
|
|
|
rect1_x = gap # 第一个矩形框的左上角x坐标
|
|
|
|
rect1_y = gap # 第一个矩形框的左上角y坐标
|
|
|
|
rect1_y = gap # 第一个矩形框的左上角y坐标
|
|
|
|
rect1_width = window_width * 1 / 3 - gap-50 # 第一个矩形框的宽度
|
|
|
|
rect1_width = window_width * 1 / 3 - gap-30 # 第一个矩形框的宽度
|
|
|
|
rect1_height = window_height * 3 / 4 - gap * 2-50 # 第一个矩形框的高度
|
|
|
|
rect1_height = window_height * 3 / 4 - gap * 2 # 第一个矩形框的高度
|
|
|
|
rect2_x = window_width * 1 / 3 + gap - 50 # 第二个矩形框的左上角x坐标
|
|
|
|
rect2_x = window_width * 1 / 3 + gap - 30 # 第二个矩形框的左上角x坐标
|
|
|
|
rect2_y = gap # 第二个矩形框的左上角y坐标
|
|
|
|
rect2_y = gap # 第二个矩形框的左上角y坐标
|
|
|
|
rect2_width = window_width * 2 / 3 - gap +50 # 第二个矩形框的宽度
|
|
|
|
rect2_width = window_width * 2 / 3 - gap + 30 # 第二个矩形框的宽度
|
|
|
|
rect2_height = window_height * 3 / 4 - gap * 2 -50 # 第二个矩形框的高度
|
|
|
|
rect2_height = window_height * 3 / 4 - gap * 2 # 第二个矩形框的高度
|
|
|
|
rect3_x = gap # 第三个矩形框的左上角x坐标
|
|
|
|
rect3_x = gap # 第三个矩形框的左上角x坐标
|
|
|
|
rect3_y = window_height * 3 / 4 + gap -50 # 第三个矩形框的左上角y坐标
|
|
|
|
rect3_y = window_height * 3 / 4 + gap # 第三个矩形框的左上角y坐标
|
|
|
|
rect3_width = window_width - gap * 2 # 第三个矩形框的宽度
|
|
|
|
rect3_width = window_width - gap * 2 # 第三个矩形框的宽度
|
|
|
|
rect3_height = window_height * 1 / 4 - gap * 2 +50 # 第三个矩形框的高度
|
|
|
|
rect3_height = window_height * 1 / 4 - gap * 2 # 第三个矩形框的高度
|
|
|
|
global Viewcanvas
|
|
|
|
global Viewcanvas
|
|
|
|
# 创建一个画布,用于绘制矩形框,设置画布的大小和背景色
|
|
|
|
# 创建一个画布,用于绘制矩形框,设置画布的大小和背景色
|
|
|
|
Viewcanvas = tk.Canvas(Root, width=window_width, height=window_height, bg="white")
|
|
|
|
Viewcanvas = tk.Canvas(Root, width=window_width, height=window_height, bg="white")
|
|
|
|
Viewcanvas.pack() # 将画布添加到主窗口中
|
|
|
|
Viewcanvas.pack() # 将画布添加到主窗口中
|
|
|
|
# 绘制矩形框,使用不同的颜色和线宽,指定矩形框的左上角和右下角坐标,填充色,边框色和边框宽度
|
|
|
|
# 绘制矩形框,使用不同的颜色和线宽,指定矩形框的左上角和右下角坐标,填充色,边框色和边框宽度
|
|
|
|
Viewcanvas.create_rectangle(rect1_x, rect1_y, rect1_x + rect1_width, rect1_y + rect1_height,
|
|
|
|
Viewcanvas.create_rectangle(rect1_x, rect1_y, rect1_x + rect1_width, rect1_y + rect1_height,
|
|
|
|
fill=None, outline="lightblue", width=2)
|
|
|
|
fill=None, outline="lightblue", width=2)
|
|
|
|
Viewcanvas.create_rectangle(rect2_x, rect2_y + 20, rect2_x + rect2_width - 20, rect2_y + rect2_height,
|
|
|
|
Viewcanvas.create_rectangle(rect2_x, rect2_y + 20, rect2_x + rect2_width - 20, rect2_y + rect2_height,
|
|
|
|
fill=None, outline="lightblue", width=2)
|
|
|
|
fill=None, outline="lightblue", width=2)
|
|
|
|
Viewcanvas.create_rectangle(rect3_x, rect3_y, rect3_x + rect3_width, rect3_y + rect3_height,
|
|
|
|
Viewcanvas.create_rectangle(rect3_x, rect3_y, rect3_x + rect3_width, rect3_y + rect3_height,
|
|
|
|
fill=None, outline="lightblue", width=2)
|
|
|
|
fill=None, outline="lightblue", width=2)
|
|
|
|
global Text
|
|
|
|
global Text
|
|
|
|
Text = st.ScrolledText(Root) # 创建一个带滚动条的文本框,用于展示计算过程
|
|
|
|
Text = st.ScrolledText(Root) # 创建一个带滚动条的文本框,用于展示计算过程
|
|
|
|
Text.place(x=rect3_x, y=rect3_y, width=1160, height=rect3_height - 1)
|
|
|
|
Text.place(x=rect3_x, y=rect3_y, width=760, height=rect3_height - 1)
|
|
|
|
# if __name__ == '__main__':
|
|
|
|
# if __name__ == '__main__':
|
|
|
|
# Root = tk.Tk()
|
|
|
|
# Root = tk.Tk()
|
|
|
|
# # 设置窗口的大小为1200*750
|
|
|
|
# # 设置窗口的大小为1200*750
|
|
|
@ -124,7 +123,7 @@ def element(path):
|
|
|
|
# 加载图元对应的图片文件
|
|
|
|
# 加载图元对应的图片文件
|
|
|
|
img=Image.open(path)
|
|
|
|
img=Image.open(path)
|
|
|
|
# 使用resize方法调整图片
|
|
|
|
# 使用resize方法调整图片
|
|
|
|
img = img.resize((70, 60))
|
|
|
|
img = img.resize((40, 30))
|
|
|
|
# 把Image对象转换成PhotoImage对象
|
|
|
|
# 把Image对象转换成PhotoImage对象
|
|
|
|
img = ImageTk.PhotoImage(img)
|
|
|
|
img = ImageTk.PhotoImage(img)
|
|
|
|
# 保存图片的引用,防止被垃圾回收
|
|
|
|
# 保存图片的引用,防止被垃圾回收
|
|
|
@ -133,47 +132,45 @@ def element(path):
|
|
|
|
|
|
|
|
|
|
|
|
def push_button():
|
|
|
|
def push_button():
|
|
|
|
button = {}
|
|
|
|
button = {}
|
|
|
|
# 指定按钮主题为 litera
|
|
|
|
style = ttk.Style(Root)
|
|
|
|
style = Style(theme='litera')
|
|
|
|
# 设置blue.TButton样式
|
|
|
|
# 设置blue.TButton样式的背景色为亮蓝灰,前景色为白色
|
|
|
|
style.configure("blue.TButton", background="LightSlateGray", foreground="black", font=("黑体", 8))
|
|
|
|
style.configure("blue.TButton", background="LightSlateGray", foreground="white", font=("黑体", 13))
|
|
|
|
style.map("blue.TButton", background=[('active', 'PowderBlue'), ('pressed', 'red')],
|
|
|
|
style.map("blue.TButton",
|
|
|
|
foreground=[('active', 'black'), ('pressed', 'white')])
|
|
|
|
background=[('active', 'PowderBlue'), ('pressed', 'red')], # 设置激活状态下的背景色为粉蓝色,按下状态下的背景色为红色
|
|
|
|
|
|
|
|
foreground=[('active', 'black'), ('pressed', 'white')]) # 设置激活状态下的前景色为黑色,按下状态下的前景色为白色
|
|
|
|
# 设置green.TButton样式
|
|
|
|
# 设置green.TButton样式的背景色为中海洋绿,前景色为白色
|
|
|
|
style.configure("green.TButton", background="MediumSeaGreen", foreground="black", font=("黑体", 8))
|
|
|
|
style.configure("green.TButton", background="MediumSeaGreen", foreground="white", font=("黑体", 13))
|
|
|
|
style.map("green.TButton", background=[('active', 'PaleGreen'), ('pressed', 'red')],
|
|
|
|
style.map("green.TButton",
|
|
|
|
foreground=[('active', 'black'), ('pressed', 'white')])
|
|
|
|
background=[('active', 'PaleGreen'), ('pressed', 'red')], # 设置激活状态下的背景色为弱绿色,按下状态下的背景色为红色
|
|
|
|
|
|
|
|
foreground=[('active', 'black'), ('pressed', 'white')]) # 设置激活状态下的前景色为黑色,按下状态下的前景色为白色
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 创建三个按钮,用于触发训练参数的设置、训练、输出模型程序的操作
|
|
|
|
# 创建三个按钮,用于触发训练参数的设置、训练、输出模型程序的操作
|
|
|
|
button1 = ttk.Button(Root, text=" 训练参数设置 ", style="blue.TButton")
|
|
|
|
button1 = ttk.Button(Root, text=" 训练参数设置 ", style="blue.TButton")
|
|
|
|
button1.place(x=20, y=500)
|
|
|
|
button1.place(x=20, y=330)
|
|
|
|
button['button1'] = button1
|
|
|
|
button['button1'] = button1
|
|
|
|
button2 = ttk.Button(Root, text=" 训练 ", style="blue.TButton")
|
|
|
|
button2 = ttk.Button(Root, text=" 训练 ", style="blue.TButton")
|
|
|
|
button2.place(x=190, y=500)
|
|
|
|
button2.place(x=140, y=330)
|
|
|
|
button['button2'] = button2
|
|
|
|
button['button2'] = button2
|
|
|
|
button3 = ttk.Button(Root, text=" 输出模型程序 ", style="blue.TButton")
|
|
|
|
button3 = ttk.Button(Root, text=" 输出模型程序 ", style="blue.TButton")
|
|
|
|
button3.place(x=300, y=500)
|
|
|
|
button3.place(x=240, y=330)
|
|
|
|
button['button3'] = button3
|
|
|
|
button['button3'] = button3
|
|
|
|
# 创建五个按钮,用于触发操作
|
|
|
|
# 创建五个按钮,用于触发操作
|
|
|
|
button4 = ttk.Button(Root, text=" 加载已有模型 ", style="green.TButton")
|
|
|
|
button4 = ttk.Button(Root, text=" 加载已有模型 ", style="green.TButton")
|
|
|
|
button4.place(x=370, y=5)
|
|
|
|
button4.place(x=255, y=10)
|
|
|
|
button['button4'] = button4
|
|
|
|
button['button4'] = button4
|
|
|
|
button5 = ttk.Button(Root, text=" 新建模型 ", style="green.TButton")
|
|
|
|
button5 = ttk.Button(Root, text=" 新建模型 ", style="green.TButton")
|
|
|
|
button5.place(x=530, y=5)
|
|
|
|
button5.place(x=355, y=10)
|
|
|
|
button['button5'] = button5
|
|
|
|
button['button5'] = button5
|
|
|
|
button6 = ttk.Button(Root, text=" 图元参数设置 ", style="green.TButton")
|
|
|
|
button6 = ttk.Button(Root, text=" 图元参数设置 ", style="green.TButton")
|
|
|
|
button6.place(x=660, y=5)
|
|
|
|
button6.place(x=435, y=10)
|
|
|
|
button['button6'] = button6
|
|
|
|
button['button6'] = button6
|
|
|
|
button7 = ttk.Button(Root, text=" 保存模型 ", style="green.TButton")
|
|
|
|
button7 = ttk.Button(Root, text=" 保存模型 ", style="green.TButton")
|
|
|
|
button7.place(x=820, y=5)
|
|
|
|
button7.place(x=535, y=10)
|
|
|
|
button['button7'] = button7
|
|
|
|
button['button7'] = button7
|
|
|
|
button8 = ttk.Button(Root, text=" 模型正确性检查 ", style="green.TButton")
|
|
|
|
button8 = ttk.Button(Root, text=" 模型正确性检查 ", style="green.TButton")
|
|
|
|
button8.place(x=940, y=5)
|
|
|
|
button8.place(x=615, y=10)
|
|
|
|
button['button8'] = button8
|
|
|
|
button['button8'] = button8
|
|
|
|
button9 = ttk.Button(Root, text="退出", style="green.TButton")
|
|
|
|
button9 = ttk.Button(Root, text="退出", style="green.TButton")
|
|
|
|
button9.place(x=1120, y=5)
|
|
|
|
button9.place(x=725, y=10)
|
|
|
|
button['button9'] = button9
|
|
|
|
button['button9'] = button9
|
|
|
|
return button
|
|
|
|
return button
|
|
|
|
|
|
|
|
|
|
|
@ -271,6 +268,7 @@ def setpool_para(numbers):
|
|
|
|
pool_list = Listinstance[2][5].split()
|
|
|
|
pool_list = Listinstance[2][5].split()
|
|
|
|
# 池大小和池类型
|
|
|
|
# 池大小和池类型
|
|
|
|
pool_mode, pool_size = pool_list[numbers-1].split(',')
|
|
|
|
pool_mode, pool_size = pool_list[numbers-1].split(',')
|
|
|
|
|
|
|
|
print(pool_size)
|
|
|
|
pool_size = int(pool_size)
|
|
|
|
pool_size = int(pool_size)
|
|
|
|
stride = 2 # 设置步长,这里假设是2
|
|
|
|
stride = 2 # 设置步长,这里假设是2
|
|
|
|
PoolPara = {numbers:{"pool_mode": pool_mode, # 返回PoolPara参数,这里用一个字典来存储
|
|
|
|
PoolPara = {numbers:{"pool_mode": pool_mode, # 返回PoolPara参数,这里用一个字典来存储
|
|
|
@ -533,113 +531,20 @@ def update_conv_layer(input, kernel, bias, loss):
|
|
|
|
bias = bias - learning_rate * bias_grad # 偏置项参数减去学习率乘以偏置项梯度
|
|
|
|
bias = bias - learning_rate * bias_grad # 偏置项参数减去学习率乘以偏置项梯度
|
|
|
|
# 返回更新后的卷积核、偏置
|
|
|
|
# 返回更新后的卷积核、偏置
|
|
|
|
return kernel, bias
|
|
|
|
return kernel, bias
|
|
|
|
def conv_one(loss,images):
|
|
|
|
|
|
|
|
global Conv1
|
|
|
|
|
|
|
|
kernel = Conv1[5][1]["kernel"]
|
|
|
|
|
|
|
|
bias = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel, new_bias = update_conv_layer(images, kernel, bias, loss)
|
|
|
|
|
|
|
|
Conv1[5][1]["kernel"] = new_kernel
|
|
|
|
|
|
|
|
Conv1[5][1]["bias"] = new_bias
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def conv_two(loss, images):
|
|
|
|
|
|
|
|
global Conv1
|
|
|
|
|
|
|
|
global Conv2
|
|
|
|
|
|
|
|
kernel1 = Conv1[5][1]["kernel"]
|
|
|
|
|
|
|
|
bias1 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel1, new_bias1 = update_conv_layer(images, kernel1, bias1, loss)
|
|
|
|
|
|
|
|
Conv1[5][1]["kernel"] = new_kernel1
|
|
|
|
|
|
|
|
Conv1[5][1]["bias"] = new_bias1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kernel2 = Conv2[5][2]["kernel"]
|
|
|
|
|
|
|
|
bias2 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel2, new_bias2 = update_conv_layer(Pool1[-1], kernel2, bias2, loss)
|
|
|
|
|
|
|
|
Conv2[5][2]["kernel"] = new_kernel2
|
|
|
|
|
|
|
|
Conv2[5][2]["bias"] = new_bias2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def conv_three(loss, images):
|
|
|
|
|
|
|
|
global Conv1
|
|
|
|
|
|
|
|
global Conv2
|
|
|
|
|
|
|
|
global Conv3
|
|
|
|
|
|
|
|
kernel1 = Conv1[5][1]["kernel"]
|
|
|
|
|
|
|
|
bias1 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel1, new_bias1 = update_conv_layer(images, kernel1, bias1, loss)
|
|
|
|
|
|
|
|
Conv1[5][1]["kernel"] = new_kernel1
|
|
|
|
|
|
|
|
Conv1[5][1]["bias"] = new_bias1
|
|
|
|
|
|
|
|
kernel2 = Conv2[5][2]["kernel"]
|
|
|
|
|
|
|
|
bias2 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel2, new_bias2 = update_conv_layer(Pool1[-1], kernel2, bias2, loss)
|
|
|
|
|
|
|
|
Conv2[5][2]["kernel"] = new_kernel2
|
|
|
|
|
|
|
|
Conv2[5][2]["bias"] = new_bias2
|
|
|
|
|
|
|
|
kernel3 = Conv3[5][3]["kernel"]
|
|
|
|
|
|
|
|
bias3 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel3, new_bias3 = update_conv_layer(Pool2[-1], kernel3, bias3, loss)
|
|
|
|
|
|
|
|
Conv3[5][3]["kernel"] = new_kernel3
|
|
|
|
|
|
|
|
Conv3[5][3]["bias"] = new_bias3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 定义一个全连接层的权重矩阵和偏置向量的调整函数,可以选择不同的激活函数
|
|
|
|
# 定义一个全连接层的权重矩阵和偏置向量的调整函数,可以选择不同的激活函数
|
|
|
|
def update_parameters(weight_matrix, bias_vector, loss):
|
|
|
|
def update_parameters(input_data, weight_matrix, bias_vector, loss, output_derivative):
|
|
|
|
# 根据激活函数的参数选择相应的函数和导数
|
|
|
|
# 根据激活函数的参数选择相应的函数和导数
|
|
|
|
# 计算权重矩阵和偏置向量的梯度,使用链式法则
|
|
|
|
# 计算权重矩阵和偏置向量的梯度,使用链式法则
|
|
|
|
|
|
|
|
weight_matrix_grad = np.dot(input_data.T, loss * output_derivative)
|
|
|
|
|
|
|
|
bias_vector_grad = np.sum(loss * output_derivative, axis=0)
|
|
|
|
learning_rate = 0.01
|
|
|
|
learning_rate = 0.01
|
|
|
|
gradient_weights = np.outer(loss, learning_rate)
|
|
|
|
|
|
|
|
# 更新权重矩阵和偏置向量
|
|
|
|
# 更新权重矩阵和偏置向量
|
|
|
|
weight_matrix = weight_matrix - gradient_weights
|
|
|
|
weight_matrix = weight_matrix - learning_rate * weight_matrix_grad
|
|
|
|
bias_vector = bias_vector - learning_rate * bias_vector
|
|
|
|
bias_vector = bias_vector - learning_rate * bias_vector_grad
|
|
|
|
# 返回更新后的权重矩阵和偏置向量
|
|
|
|
# 返回更新后的权重矩阵和偏置向量
|
|
|
|
return weight_matrix, bias_vector
|
|
|
|
return weight_matrix, bias_vector
|
|
|
|
def fully_one(loss):
|
|
|
|
|
|
|
|
global Fullconn1
|
|
|
|
|
|
|
|
weight1 = Fullconn1[5][1]["weights"]
|
|
|
|
|
|
|
|
bias1 = Fullconn1[5][1]["bias"]
|
|
|
|
|
|
|
|
loss = np.array([loss])
|
|
|
|
|
|
|
|
new_weight1, new_bias1 = update_parameters(weight1, bias1, loss)
|
|
|
|
|
|
|
|
Fullconn1[5][1]["weights"] = new_weight1
|
|
|
|
|
|
|
|
Fullconn1[5][1]["bias"] = new_bias1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fully_two(loss):
|
|
|
|
|
|
|
|
global Fullconn1
|
|
|
|
|
|
|
|
global Fullconn2
|
|
|
|
|
|
|
|
weight1 = Fullconn1[5][1]["weights"]
|
|
|
|
|
|
|
|
bias1 = Fullconn1[5][1]["bias"]
|
|
|
|
|
|
|
|
loss = np.array([loss])
|
|
|
|
|
|
|
|
new_weight1, new_bias1 = update_parameters(weight1, bias1, loss)
|
|
|
|
|
|
|
|
Fullconn1[5][1]["weights"] = new_weight1
|
|
|
|
|
|
|
|
Fullconn1[5][1]["bias"] = new_bias1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weight2 = Fullconn2[5][1]["weights"]
|
|
|
|
|
|
|
|
bias2 = Fullconn2[5][1]["bias"]
|
|
|
|
|
|
|
|
new_weight2, new_bias2 = update_parameters(weight2, bias2, loss)
|
|
|
|
|
|
|
|
Fullconn2[5][1]["weights"] = new_weight2
|
|
|
|
|
|
|
|
Fullconn2[5][1]["bias"] = new_bias2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fully_three(loss):
|
|
|
|
|
|
|
|
global Fullconn1
|
|
|
|
|
|
|
|
global Fullconn2
|
|
|
|
|
|
|
|
global Fullconn3
|
|
|
|
|
|
|
|
weight1 = Fullconn1[5][1]["weights"]
|
|
|
|
|
|
|
|
bias1 = Fullconn1[5][1]["bias"]
|
|
|
|
|
|
|
|
loss = np.array([loss])
|
|
|
|
|
|
|
|
new_weight1, new_bias1 = update_parameters(weight1, bias1, loss)
|
|
|
|
|
|
|
|
Fullconn1[5][1]["weights"] = new_weight1
|
|
|
|
|
|
|
|
Fullconn1[5][1]["bias"] = new_bias1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weight2 = Fullconn2[5][1]["weights"]
|
|
|
|
|
|
|
|
bias2 = Fullconn2[5][1]["bias"]
|
|
|
|
|
|
|
|
new_weight2, new_bias2 = update_parameters(weight2, bias2, loss)
|
|
|
|
|
|
|
|
Fullconn2[5][1]["weights"] = new_weight2
|
|
|
|
|
|
|
|
Fullconn2[5][1]["bias"] = new_bias2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weight3 = Fullconn3[5][3]["weights"]
|
|
|
|
|
|
|
|
bias3 = Fullconn3[5][1]["bias"]
|
|
|
|
|
|
|
|
new_weight3, new_bias3 = update_parameters(weight3, bias3, loss)
|
|
|
|
|
|
|
|
Fullconn3[5][3]["weights"] = new_weight3
|
|
|
|
|
|
|
|
Fullconn3[5][3]["bias"] = new_bias3
|
|
|
|
|
|
|
|
# X4交互式构建卷积神经网络模型
|
|
|
|
# X4交互式构建卷积神经网络模型
|
|
|
|
# 定义图元拖拽开始的函数
|
|
|
|
# 定义图元拖拽开始的函数
|
|
|
|
def on_drag_start(event):
|
|
|
|
def on_drag_start(event):
|
|
|
@ -783,7 +688,9 @@ def fully_connected(event):
|
|
|
|
event.widget.coords(Dragged_item, Original_x, Original_y)
|
|
|
|
event.widget.coords(Dragged_item, Original_x, Original_y)
|
|
|
|
# 将新图元的id和坐标添加到列表中
|
|
|
|
# 将新图元的id和坐标添加到列表中
|
|
|
|
Items1.append((new_item1, x, Yt))
|
|
|
|
Items1.append((new_item1, x, Yt))
|
|
|
|
top = creat_window("全连接参数配置")
|
|
|
|
top = tk.Toplevel(Root) # 创建弹出窗口
|
|
|
|
|
|
|
|
top.geometry("300x250")
|
|
|
|
|
|
|
|
top.title("全连接参数配置")
|
|
|
|
num_outputs_entry = create_input_box(top, "全连接输出维度:", 10)
|
|
|
|
num_outputs_entry = create_input_box(top, "全连接输出维度:", 10)
|
|
|
|
# 创建
|
|
|
|
# 创建
|
|
|
|
def get_input():
|
|
|
|
def get_input():
|
|
|
@ -846,13 +753,20 @@ def class_ification(event):
|
|
|
|
event.widget.coords(Dragged_item, Original_x, Original_y)
|
|
|
|
event.widget.coords(Dragged_item, Original_x, Original_y)
|
|
|
|
# 将新图元的id和坐标添加到列表中
|
|
|
|
# 将新图元的id和坐标添加到列表中
|
|
|
|
Items1.append((new_item1, x, Yt))
|
|
|
|
Items1.append((new_item1, x, Yt))
|
|
|
|
top = creat_window('分类参数配置') # 创建弹出窗口
|
|
|
|
top = tk.Toplevel(Root) # 创建弹出窗口
|
|
|
|
# 创建一个下拉框,用于选择非线性类型
|
|
|
|
top.geometry("300x250")
|
|
|
|
class_box_combobox = create_input_box(top, "阈值:", 0.001) # 创建一个下拉框,用于选择池化类型
|
|
|
|
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():
|
|
|
|
def get_input():
|
|
|
|
# 从输入框中获取阈值
|
|
|
|
# 从输入框中获取阈值
|
|
|
|
threshold = float(class_box_combobox.get())
|
|
|
|
threshold = float(threshold_entry.get())
|
|
|
|
# 复制对象的标签
|
|
|
|
# 复制对象的标签
|
|
|
|
Viewcanvas.create_text(x, Yt + 40, text="输出分类结果")
|
|
|
|
Viewcanvas.create_text(x, Yt + 40, text="输出分类结果")
|
|
|
|
if Listinstance[5][5] == ".":
|
|
|
|
if Listinstance[5][5] == ".":
|
|
|
@ -919,6 +833,7 @@ def adjust_one(event):
|
|
|
|
# 将新图元的id和坐标添加到列表中
|
|
|
|
# 将新图元的id和坐标添加到列表中
|
|
|
|
Items1.append((new_item1, x, y))
|
|
|
|
Items1.append((new_item1, x, y))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_two(event):
|
|
|
|
def adjust_two(event):
|
|
|
|
global Viewcanvas
|
|
|
|
global Viewcanvas
|
|
|
|
global Items1
|
|
|
|
global Items1
|
|
|
@ -1055,7 +970,7 @@ def element_binding(obj_x, obj_y, image, y, text):
|
|
|
|
# 创建图元对象
|
|
|
|
# 创建图元对象
|
|
|
|
l1 = Viewcanvas.create_image(obj_x, obj_y, image=image)
|
|
|
|
l1 = Viewcanvas.create_image(obj_x, obj_y, image=image)
|
|
|
|
# 创建图元对象的标签
|
|
|
|
# 创建图元对象的标签
|
|
|
|
Viewcanvas.create_text(obj_x - 70, obj_y + y, text=text, font=("黑体", 14))
|
|
|
|
Viewcanvas.create_text(obj_x - 40, obj_y + y, text=text, font=("黑体", 8))
|
|
|
|
return l1
|
|
|
|
return l1
|
|
|
|
|
|
|
|
|
|
|
|
def create_left_element(AllModelObj,List_image):
|
|
|
|
def create_left_element(AllModelObj,List_image):
|
|
|
@ -1120,21 +1035,21 @@ def train_setting():
|
|
|
|
button = tk.Button(top, text="获取信息", command=get_input)
|
|
|
|
button = tk.Button(top, text="获取信息", command=get_input)
|
|
|
|
button.pack()
|
|
|
|
button.pack()
|
|
|
|
|
|
|
|
|
|
|
|
def conn_forward(count,layer,outputs):
|
|
|
|
def conn_forward(counts,layer,outputs):
|
|
|
|
# 若为第一层卷积层且该层的图元实例Conv1还未创建
|
|
|
|
# 若为第一层卷积层且该层的图元实例Conv1还未创建
|
|
|
|
if count[layer] == 1 and Conv1 == None:
|
|
|
|
if counts[layer] == 1 and Conv1 is None:
|
|
|
|
# 调用SetConvPara()函数,获取卷积层1参数
|
|
|
|
# 调用SetConvPara()函数,获取卷积层1参数
|
|
|
|
ConvPara = setconv_para(1)
|
|
|
|
ConvPara = setconv_para(counts[layer])
|
|
|
|
# 若图元实例Conv1已经被定义,说明需要根据反向传播调整卷积核
|
|
|
|
# 若图元实例Conv1已经被定义,说明需要根据反向传播调整卷积核
|
|
|
|
if count[layer] == 1 and Conv1 != None:
|
|
|
|
if counts[layer] == 1 and Conv1 is not None:
|
|
|
|
ConvPara = Conv1[5][1]
|
|
|
|
ConvPara = Conv1[5][1]
|
|
|
|
if count[layer] == 2 and Conv2 == None:
|
|
|
|
if counts[layer] == 2 and Conv2 is None:
|
|
|
|
ConvPara = setconv_para(count[layer])
|
|
|
|
ConvPara = setconv_para(counts[layer])
|
|
|
|
if count[layer] == 2 and Conv2 != None:
|
|
|
|
if counts[layer] == 2 and Conv2 is not None:
|
|
|
|
ConvPara = Conv2[5][2]
|
|
|
|
ConvPara = Conv2[5][2]
|
|
|
|
if count[layer] == 3 and Conv3 == None:
|
|
|
|
if counts[layer] == 3 and Conv3 is None:
|
|
|
|
ConvPara = setconv_para(count[layer])
|
|
|
|
ConvPara = setconv_para(counts[layer])
|
|
|
|
if count[layer] == 3 and Conv3 != None:
|
|
|
|
if counts[layer] == 3 and Conv3 is not None:
|
|
|
|
ConvPara = Conv3[5][3]
|
|
|
|
ConvPara = Conv3[5][3]
|
|
|
|
# 初始化一个空列表来存储池化后的结果
|
|
|
|
# 初始化一个空列表来存储池化后的结果
|
|
|
|
new_outputs = []
|
|
|
|
new_outputs = []
|
|
|
@ -1160,22 +1075,22 @@ def conn_forward(count,layer,outputs):
|
|
|
|
print(outputs[0])
|
|
|
|
print(outputs[0])
|
|
|
|
print("")
|
|
|
|
print("")
|
|
|
|
return outputs
|
|
|
|
return outputs
|
|
|
|
def pool_forward(count,layer,outputs):
|
|
|
|
def pool_forward(counts,layer,outputs):
|
|
|
|
global Pool1
|
|
|
|
global Pool1
|
|
|
|
global Pool2
|
|
|
|
global Pool2
|
|
|
|
global Pool3
|
|
|
|
global Pool3
|
|
|
|
if count[layer] == 1 and Pool1 == None:
|
|
|
|
if counts[layer] == 1 and Pool1 is None:
|
|
|
|
# 调用设置池化层参数的函数,获取池化参数
|
|
|
|
# 调用设置池化层参数的函数,获取池化参数
|
|
|
|
PoolPara = setpool_para(count[layer])
|
|
|
|
PoolPara = setpool_para(counts[layer])
|
|
|
|
if count[layer] == 1 and Pool1 != None:
|
|
|
|
if counts[layer] == 1 and Pool1 is not None:
|
|
|
|
PoolPara = Pool1[5][1]
|
|
|
|
PoolPara = Pool1[5][1]
|
|
|
|
if count[layer] == 2 and Pool2 == None:
|
|
|
|
if counts[layer] == 2 and Pool2 is None:
|
|
|
|
PoolPara = setpool_para(count[layer])
|
|
|
|
PoolPara = setpool_para(counts[layer])
|
|
|
|
if count[layer] == 2 and Pool2 != None:
|
|
|
|
if counts[layer] == 2 and Pool2 is not None:
|
|
|
|
PoolPara = Pool2[5][2]
|
|
|
|
PoolPara = Pool2[5][2]
|
|
|
|
if count[layer] == 3 and Pool3 == None:
|
|
|
|
if counts[layer] == 3 and Pool3 is None:
|
|
|
|
PoolPara = setpool_para(count[layer])
|
|
|
|
PoolPara = setpool_para(counts[layer])
|
|
|
|
if count[layer] == 3 and Pool3 != None:
|
|
|
|
if counts[layer] == 3 and Pool3 is not None:
|
|
|
|
PoolPara = Pool3[5][3]
|
|
|
|
PoolPara = Pool3[5][3]
|
|
|
|
# 初始化一个空列表来存储池化后的结果
|
|
|
|
# 初始化一个空列表来存储池化后的结果
|
|
|
|
new_outputs = []
|
|
|
|
new_outputs = []
|
|
|
@ -1184,33 +1099,33 @@ def pool_forward(count,layer,outputs):
|
|
|
|
new_outputs.append(pool_proc(output, PoolPara))
|
|
|
|
new_outputs.append(pool_proc(output, PoolPara))
|
|
|
|
# 将new_outputs赋值给outputs
|
|
|
|
# 将new_outputs赋值给outputs
|
|
|
|
outputs = new_outputs
|
|
|
|
outputs = new_outputs
|
|
|
|
if count[layer] == 1:
|
|
|
|
if counts[layer] == 1:
|
|
|
|
Pool1.append(outputs)
|
|
|
|
Pool1.append(outputs)
|
|
|
|
if count[layer] == 2:
|
|
|
|
if counts[layer] == 2:
|
|
|
|
Pool2.append(outputs)
|
|
|
|
Pool2.append(outputs)
|
|
|
|
if count[layer] == 3:
|
|
|
|
if counts[layer] == 3:
|
|
|
|
Pool3.append(outputs)
|
|
|
|
Pool3.append(outputs)
|
|
|
|
print("池化处理结果:")
|
|
|
|
print("池化处理结果:")
|
|
|
|
print(outputs[0])
|
|
|
|
print(outputs[0])
|
|
|
|
print("")
|
|
|
|
print("")
|
|
|
|
return outputs
|
|
|
|
return outputs
|
|
|
|
|
|
|
|
|
|
|
|
def fullconn_forward(count,layer,outputs):
|
|
|
|
def fullconn_forward(counts,layer,outputs):
|
|
|
|
output = outputs[0]
|
|
|
|
output = outputs[0]
|
|
|
|
# 若图元实例Fullconn1未被定义
|
|
|
|
# 若图元实例Fullconn1未被定义
|
|
|
|
if count[layer] == 1 and Fullconn1 == None:
|
|
|
|
if counts[layer] == 1 and Fullconn1 is None:
|
|
|
|
# 调用设置全连接层参数的函数,获取全连接参数
|
|
|
|
# 调用设置全连接层参数的函数,获取全连接参数
|
|
|
|
FullConnPara = setfullconn_para(output, count[layer])
|
|
|
|
FullConnPara = setfullconn_para(output, counts[layer])
|
|
|
|
# 若图元实例Fullconn1已经被定义,说明需要根据反向传播调整权重矩阵和偏置向量
|
|
|
|
# 若图元实例Fullconn1已经被定义,说明需要根据反向传播调整权重矩阵和偏置向量
|
|
|
|
if count[layer] == 1 and Fullconn1 != None:
|
|
|
|
if counts[layer] == 1 and Fullconn1 is not None:
|
|
|
|
FullConnPara = Fullconn1[5][1]
|
|
|
|
FullConnPara = Fullconn1[5][1]
|
|
|
|
if count[layer] == 2 and Fullconn2 == None:
|
|
|
|
if counts[layer] == 2 and Fullconn2 is None:
|
|
|
|
FullConnPara = setfullconn_para(output, count[layer])
|
|
|
|
FullConnPara = setfullconn_para(output, counts[layer])
|
|
|
|
if count[layer] == 2 and Fullconn2 != None:
|
|
|
|
if counts[layer] == 2 and Fullconn2 is not None:
|
|
|
|
FullConnPara = Fullconn2[5][2]
|
|
|
|
FullConnPara = Fullconn2[5][2]
|
|
|
|
if count[layer] == 3 and Fullconn3 == None:
|
|
|
|
if counts[layer] == 3 and Fullconn3 is None:
|
|
|
|
FullConnPara = setfullconn_para(output, count[layer])
|
|
|
|
FullConnPara = setfullconn_para(output, counts[layer])
|
|
|
|
if count[layer] == 3 and Fullconn3 != None:
|
|
|
|
if counts[layer] == 3 and Fullconn3 is not None:
|
|
|
|
FullConnPara = Fullconn3[5][3]
|
|
|
|
FullConnPara = Fullconn3[5][3]
|
|
|
|
# 初始化一个空列表来存储池化后的结果
|
|
|
|
# 初始化一个空列表来存储池化后的结果
|
|
|
|
new_outputs = []
|
|
|
|
new_outputs = []
|
|
|
@ -1257,6 +1172,7 @@ def classifier_forward(outputs):
|
|
|
|
x -= np.max(x)
|
|
|
|
x -= np.max(x)
|
|
|
|
# 计算指数和归一化
|
|
|
|
# 计算指数和归一化
|
|
|
|
return np.exp(x) / np.sum(np.exp(x))
|
|
|
|
return np.exp(x) / np.sum(np.exp(x))
|
|
|
|
|
|
|
|
|
|
|
|
# 对outputs列表中的每个元素调用ClassifierProc函数,并将结果添加到new_outputs列表中
|
|
|
|
# 对outputs列表中的每个元素调用ClassifierProc函数,并将结果添加到new_outputs列表中
|
|
|
|
for output in outputs:
|
|
|
|
for output in outputs:
|
|
|
|
new_outputs.append(classifier_proc(output, ClassifyPara))
|
|
|
|
new_outputs.append(classifier_proc(output, ClassifyPara))
|
|
|
@ -1295,6 +1211,55 @@ def forward_propagation(Train_images):
|
|
|
|
outputs = np.array(outputs)# 将输出结果列表转换为数组形式,方便后续处理
|
|
|
|
outputs = np.array(outputs)# 将输出结果列表转换为数组形式,方便后续处理
|
|
|
|
return outputs# 返回输出结果数组
|
|
|
|
return outputs# 返回输出结果数组
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def conv_one(loss,images):
|
|
|
|
|
|
|
|
global Conv1
|
|
|
|
|
|
|
|
kernel = Conv1[5][1]["kernel"]
|
|
|
|
|
|
|
|
bias = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel, new_bias = update_conv_layer(images, kernel, bias, loss)
|
|
|
|
|
|
|
|
Conv1[5][1]["kernel"] = new_kernel
|
|
|
|
|
|
|
|
Conv1[5][1]["bias"] = new_bias
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def conv_two(loss, images):
|
|
|
|
|
|
|
|
global Conv1
|
|
|
|
|
|
|
|
global Conv2
|
|
|
|
|
|
|
|
kernel1 = Conv1[5][1]["kernel"]
|
|
|
|
|
|
|
|
bias1 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel1, new_bias1 = update_conv_layer(images, kernel1, bias1, loss)
|
|
|
|
|
|
|
|
Conv1[5][1]["kernel"] = new_kernel1
|
|
|
|
|
|
|
|
Conv1[5][1]["bias"] = new_bias1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kernel2 = Conv2[5][2]["kernel"]
|
|
|
|
|
|
|
|
bias2 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel2, new_bias2 = update_conv_layer(Pool1[-1], kernel2, bias2, loss)
|
|
|
|
|
|
|
|
Conv2[5][2]["kernel"] = new_kernel2
|
|
|
|
|
|
|
|
Conv2[5][2]["bias"] = new_bias2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def conv_three(loss, images):
|
|
|
|
|
|
|
|
global Conv1
|
|
|
|
|
|
|
|
global Conv2
|
|
|
|
|
|
|
|
global Conv3
|
|
|
|
|
|
|
|
kernel1 = Conv1[5][1]["kernel"]
|
|
|
|
|
|
|
|
bias1 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel1, new_bias1 = update_conv_layer(images, kernel1, bias1, loss)
|
|
|
|
|
|
|
|
Conv1[5][1]["kernel"] = new_kernel1
|
|
|
|
|
|
|
|
Conv1[5][1]["bias"] = new_bias1
|
|
|
|
|
|
|
|
kernel2 = Conv2[5][2]["kernel"]
|
|
|
|
|
|
|
|
bias2 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel2, new_bias2 = update_conv_layer(Pool1[-1], kernel2, bias2, loss)
|
|
|
|
|
|
|
|
Conv2[5][2]["kernel"] = new_kernel2
|
|
|
|
|
|
|
|
Conv2[5][2]["bias"] = new_bias2
|
|
|
|
|
|
|
|
kernel3 = Conv3[5][3]["kernel"]
|
|
|
|
|
|
|
|
bias3 = 0.5
|
|
|
|
|
|
|
|
loss = np.array([[loss]])
|
|
|
|
|
|
|
|
new_kernel3, new_bias3 = update_conv_layer(Pool2[-1], kernel3, bias3, loss)
|
|
|
|
|
|
|
|
Conv3[5][3]["kernel"] = new_kernel3
|
|
|
|
|
|
|
|
Conv3[5][3]["bias"] = new_bias3
|
|
|
|
|
|
|
|
|
|
|
|
def determine(Train_list,Items3):
|
|
|
|
def determine(Train_list,Items3):
|
|
|
|
if len(Train_list) == 0:
|
|
|
|
if len(Train_list) == 0:
|
|
|
|
messagebox.showerror("错误", "请设置训练参数!")
|
|
|
|
messagebox.showerror("错误", "请设置训练参数!")
|
|
|
@ -1331,33 +1296,23 @@ def train():# 训练
|
|
|
|
loss = error_proc(Prob_images, right_label, ErrorPara) * 0.1 # 计算误差值
|
|
|
|
loss = error_proc(Prob_images, right_label, ErrorPara) * 0.1 # 计算误差值
|
|
|
|
print("当前epoch:",first_epoch,i * batch_size,":",(i + 1) * batch_size,"误差值:",loss)
|
|
|
|
print("当前epoch:",first_epoch,i * batch_size,":",(i + 1) * batch_size,"误差值:",loss)
|
|
|
|
print("")
|
|
|
|
print("")
|
|
|
|
if (Conv2 == None) and (Conv3 == None):
|
|
|
|
if Conv2 and Conv3 is None:
|
|
|
|
conv_one(loss,images)
|
|
|
|
conv_one(loss, images)
|
|
|
|
elif (Conv2 != None) and (Conv3 == None):
|
|
|
|
elif Conv2 is not None and Conv3 is None:
|
|
|
|
conv_two(loss,images)
|
|
|
|
conv_two(loss, images)
|
|
|
|
elif (Conv3 != None):
|
|
|
|
elif Conv3 is not None:
|
|
|
|
conv_three(loss,images)
|
|
|
|
conv_three(loss, images)
|
|
|
|
if (Fullconn2 == None) and (Fullconn3 == None):
|
|
|
|
|
|
|
|
fully_one(loss)
|
|
|
|
|
|
|
|
elif (Fullconn2 != None) and (Fullconn3 == None):
|
|
|
|
|
|
|
|
fully_two(loss)
|
|
|
|
|
|
|
|
elif (Fullconn3 != None):
|
|
|
|
|
|
|
|
fully_three(loss)
|
|
|
|
|
|
|
|
# 输出模型程序
|
|
|
|
# 输出模型程序
|
|
|
|
def model_show():
|
|
|
|
def model_show():
|
|
|
|
pixel = ['数据集','卷积','池化','全连接','非线性','分类','误差','调整1','调整2','调整3']
|
|
|
|
print(Items3)
|
|
|
|
pixel_items3 = []
|
|
|
|
|
|
|
|
for i in Items3:
|
|
|
|
|
|
|
|
pixel_items3.append(pixel[i])
|
|
|
|
|
|
|
|
print(pixel_items3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def connecting_lines(obj_x, obj_y, index, x, y, x1, x2, y1, y2, y3 , image, text, smooth, width):
|
|
|
|
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_image(obj_x+(index + x) * 80, obj_y, image=image)
|
|
|
|
# 创建图元对象的标签
|
|
|
|
# 创建图元对象的标签
|
|
|
|
Viewcanvas.create_text(obj_x+(index + x) * 110, obj_y + y1, text=text, font=("黑体", 14))
|
|
|
|
Viewcanvas.create_text(obj_x+(index + x) * 80, obj_y + y1, text=text, font=("黑体", 8))
|
|
|
|
# 创建数据线箭头
|
|
|
|
# 创建数据线箭头
|
|
|
|
Viewcanvas.create_line(obj_x+(index + x) * 110 +x1, obj_y + y2, obj_x+(index + y) * 110 +x2, obj_y + y3, arrow=tk.LAST,
|
|
|
|
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=width)
|
|
|
|
arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth, width=width)
|
|
|
|
|
|
|
|
|
|
|
|
def number_judgments(lsts):
|
|
|
|
def number_judgments(lsts):
|
|
|
@ -1407,9 +1362,9 @@ def load_file():
|
|
|
|
|
|
|
|
|
|
|
|
def connecting(obj_x, obj_y, index, x, y1, image, text):
|
|
|
|
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_image(obj_x+(index + x) * 80, obj_y, image=image)
|
|
|
|
# 创建图元对象的标签
|
|
|
|
# 创建图元对象的标签
|
|
|
|
Viewcanvas.create_text(obj_x+(index + x) * 110, obj_y + y1, text=text, font=("黑体", 14))
|
|
|
|
Viewcanvas.create_text(obj_x+(index + x) * 80, obj_y + y1, text=text, font=("黑体", 8))
|
|
|
|
# 加载已有模型
|
|
|
|
# 加载已有模型
|
|
|
|
def load_model():
|
|
|
|
def load_model():
|
|
|
|
import copy
|
|
|
|
import copy
|
|
|
@ -1420,6 +1375,7 @@ def load_model():
|
|
|
|
global Viewcanvas
|
|
|
|
global Viewcanvas
|
|
|
|
global Listinstance
|
|
|
|
global Listinstance
|
|
|
|
global Viewcanvas
|
|
|
|
global Viewcanvas
|
|
|
|
|
|
|
|
Viewcanvas.delete('all')
|
|
|
|
create_left_element(AllModelObj, List_image)
|
|
|
|
create_left_element(AllModelObj, List_image)
|
|
|
|
Train_images, Test_images = load_data(DataPara) # load_data()函数,根据参数加载数据集
|
|
|
|
Train_images, Test_images = load_data(DataPara) # load_data()函数,根据参数加载数据集
|
|
|
|
# 打印一些信息,检查是否正确加载
|
|
|
|
# 打印一些信息,检查是否正确加载
|
|
|
@ -1427,82 +1383,66 @@ def load_model():
|
|
|
|
print("测试集图片的形状:", Test_images.shape)
|
|
|
|
print("测试集图片的形状:", Test_images.shape)
|
|
|
|
# 根据pkl文件的前向传播顺序列表,依次识别卷积层、池化层、全连接层、非线性层和分类层的操作
|
|
|
|
# 根据pkl文件的前向传播顺序列表,依次识别卷积层、池化层、全连接层、非线性层和分类层的操作
|
|
|
|
count,counts,sequence = number_judgments(lsts)
|
|
|
|
count,counts,sequence = number_judgments(lsts)
|
|
|
|
x,y = 420,300
|
|
|
|
x,y = 290,200
|
|
|
|
connecting_lines(x, y, 0, 0, 0, 25, 60, 45, 0, 0, List_image[0], '数据集', True, 2)
|
|
|
|
connecting_lines(x, y, 0, 0, 0, 25, 60, 45, 0, 0, List_image[0], '数据集', True, 1)
|
|
|
|
for layer in range(len(count)):
|
|
|
|
for layer in range(len(count)):
|
|
|
|
if count[layer] == 2: # 如果是卷积层,将读取的卷积层的信息存储到Conv实例
|
|
|
|
if count[layer] == 2: # 如果是卷积层,将读取的卷积层的信息存储到Conv实例
|
|
|
|
if counts[layer]%10 == 1:
|
|
|
|
if counts[layer]%10 == 1:
|
|
|
|
global Conv1
|
|
|
|
global Conv1
|
|
|
|
Listinstance[1] = copy.deepcopy(lsts[sequence[layer]])
|
|
|
|
Listinstance[1] = copy.deepcopy(lsts[sequence[layer]])
|
|
|
|
Conv1 = lsts[sequence[layer]]
|
|
|
|
Conv1 = lsts[sequence[layer]]
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层1', True, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层1', True, 1)
|
|
|
|
if counts[layer]%10 == 2:
|
|
|
|
if counts[layer]%10 == 2:
|
|
|
|
global Conv2
|
|
|
|
global Conv2
|
|
|
|
Conv2 = lsts[sequence[layer]]
|
|
|
|
Conv2 = lsts[sequence[layer]]
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层2', True, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层2', True, 1)
|
|
|
|
if counts[layer]%10 == 3:
|
|
|
|
if counts[layer]%10 == 3:
|
|
|
|
global Conv3
|
|
|
|
global Conv3
|
|
|
|
Conv3 = lsts[sequence[layer]]
|
|
|
|
Conv3 = lsts[sequence[layer]]
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层3', True, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[1], '卷积层3', True, 3)
|
|
|
|
if count[layer] == 3: # 如果是池化层,将读取的池化层的信息存储到Pool实例
|
|
|
|
if count[layer] == 3: # 如果是池化层,将读取的池化层的信息存储到Pool实例
|
|
|
|
if counts[layer]%10 == 1:
|
|
|
|
if counts[layer]%10 == 1:
|
|
|
|
global Pool1
|
|
|
|
global Pool1
|
|
|
|
Listinstance[2] =copy.deepcopy(lsts[sequence[layer]])
|
|
|
|
Listinstance[2] =copy.deepcopy(lsts[sequence[layer]])
|
|
|
|
Pool1 = lsts[sequence[layer]]
|
|
|
|
Pool1 = lsts[sequence[layer]]
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化1', True, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化1', True, 3)
|
|
|
|
if counts[layer]%10 == 2:
|
|
|
|
if counts[layer]%10 == 2:
|
|
|
|
global Pool2
|
|
|
|
global Pool2
|
|
|
|
Pool2 = lsts[sequence[layer]]
|
|
|
|
Pool2 = lsts[sequence[layer]]
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化2', True, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化2', True, 3)
|
|
|
|
if counts[layer]%10 == 3:
|
|
|
|
if counts[layer]%10 == 3:
|
|
|
|
global Pool3
|
|
|
|
global Pool3
|
|
|
|
Pool3 = lsts[sequence[layer]]
|
|
|
|
Pool3 = lsts[sequence[layer]]
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化3', True, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[2], '池化3', True, 3)
|
|
|
|
if count[layer] == 4: # 如果是全连接层,将读取的全连接层的信息存储到Pool实例
|
|
|
|
if count[layer] == 4: # 如果是全连接层,将读取的全连接层的信息存储到Pool实例
|
|
|
|
if counts[layer]%10 == 1:
|
|
|
|
if counts[layer]%10 == 1:
|
|
|
|
global Fullconn1
|
|
|
|
global Fullconn1
|
|
|
|
Listinstance[3] = lsts[sequence[layer]]
|
|
|
|
Listinstance[3] = lsts[sequence[layer]]
|
|
|
|
Fullconn1 = copy.deepcopy(lsts[sequence[layer]])# 深拷贝创建了一个全新的对象,要使用深拷贝,不然报错
|
|
|
|
Fullconn1 = copy.deepcopy(lsts[sequence[layer]])# 深拷贝创建了一个全新的对象,要使用深拷贝,不然报错
|
|
|
|
Listinstance[3][5] = str(Fullconn1[5][1]["num_outputs"])
|
|
|
|
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, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[3], '全连接1', True, 3)
|
|
|
|
if counts[layer]%10 == 2:
|
|
|
|
if counts[layer]%10 == 2:
|
|
|
|
global Fullconn2
|
|
|
|
global Fullconn2
|
|
|
|
Fullconn2 = lsts[sequence[layer]]
|
|
|
|
Fullconn2 = lsts[sequence[layer]]
|
|
|
|
# FullConn[5] = FullConn[5] + " " + str(Fullconn2[5][2]["num_outputs"])
|
|
|
|
# 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, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[3], '全连接3', True, 3)
|
|
|
|
if counts[layer]%10 == 3:
|
|
|
|
if counts[layer]%10 == 3:
|
|
|
|
global Fullconn3
|
|
|
|
global Fullconn3
|
|
|
|
Fullconn3 = lsts[sequence[layer]]
|
|
|
|
Fullconn3 = lsts[sequence[layer]]
|
|
|
|
# FullConn[5] = FullConn[5] + " " + str(Fullconn3[5][3]["num_outputs"])
|
|
|
|
# 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, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[3], '全连接3', True, 3)
|
|
|
|
if count[layer] == 5: # 如果是非线性层,将读取的非线性层的信息存储到Nonline实例
|
|
|
|
if count[layer] == 5: # 如果是非线性层,将读取的非线性层的信息存储到Nonline实例
|
|
|
|
Listinstance[4] = lsts[sequence[layer]]
|
|
|
|
Listinstance[4] = lsts[sequence[layer]]
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[4], '非线性', True, 2)
|
|
|
|
connecting_lines(x, y, layer, 1, 2, 25, -25, 45, 0, 0, List_image[4], '非线性', True, 3)
|
|
|
|
if count[layer] == 6: # 如果是分类输出层,将读取的信息存储到Nonline实例
|
|
|
|
if count[layer] == 6: # 如果是分类输出层,将读取的信息存储到Nonline实例
|
|
|
|
Listinstance[5] = lsts[sequence[layer]]
|
|
|
|
Listinstance[5] = lsts[sequence[layer]]
|
|
|
|
connecting(x, y, layer, 1, 45,List_image[5], '分类')
|
|
|
|
connecting(x, y, layer, 1, 45,List_image[5], '分类')
|
|
|
|
if count[layer] == 7: # 如果是计算误差层,将读取的信息存储到Error实例
|
|
|
|
if count[layer] == 7: # 如果是计算误差层,将读取的信息存储到Error实例
|
|
|
|
Listinstance[6] = lsts[sequence[layer]]
|
|
|
|
Listinstance[6] = lsts[sequence[layer]]
|
|
|
|
connecting(x - 30, y - 120, layer, 0, 45, List_image[6], '计算误差')
|
|
|
|
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,
|
|
|
|
Viewcanvas.create_line(x + 5 * 80 + 25, y, x + 5 * 80 + 20, y - 80,
|
|
|
|
x + 5 * 110 - 20, y - 120, arrow=tk.LAST, arrowshape=(16, 20, 4),
|
|
|
|
x + 5 * 80 - 20, y - 120, arrow=tk.LAST, arrowshape=(16, 20, 4),
|
|
|
|
fill='lightblue', smooth=True, width=2)
|
|
|
|
fill='lightblue', smooth=True, width=1)
|
|
|
|
# 创建图元对象
|
|
|
|
|
|
|
|
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):
|
|
|
|
def create_window(number,count,list1,list2,list3,list4,list5,list6):
|
|
|
|
global Listinstance
|
|
|
|
global Listinstance
|
|
|
@ -1884,16 +1824,12 @@ def count_model(layer):
|
|
|
|
if layer == 6:
|
|
|
|
if layer == 6:
|
|
|
|
with open("list.pkl", "ab") as f:
|
|
|
|
with open("list.pkl", "ab") as f:
|
|
|
|
pickle.dump(Listinstance[6], f)
|
|
|
|
pickle.dump(Listinstance[6], f)
|
|
|
|
|
|
|
|
|
|
|
|
# 保存网络模型
|
|
|
|
# 保存网络模型
|
|
|
|
def save_model():
|
|
|
|
def save_model():
|
|
|
|
if len(Items3) == 0:
|
|
|
|
if len(Items3) == 0:
|
|
|
|
messagebox.showerror("错误", "请添加图元!")
|
|
|
|
messagebox.showerror("错误", "请添加图元!")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
file_path = 'list.pkl'
|
|
|
|
|
|
|
|
# 检查文件是否存在
|
|
|
|
|
|
|
|
if os.path.exists(file_path):
|
|
|
|
|
|
|
|
# 删除文件
|
|
|
|
|
|
|
|
os.remove(file_path)
|
|
|
|
|
|
|
|
# 生成试验数据集,用于保存模型
|
|
|
|
# 生成试验数据集,用于保存模型
|
|
|
|
Test_images = np.random.rand(100, 48, 48) * 0.01
|
|
|
|
Test_images = np.random.rand(100, 48, 48) * 0.01
|
|
|
|
# 对试验数据集进行前向传播的计算
|
|
|
|
# 对试验数据集进行前向传播的计算
|
|
|
@ -1934,12 +1870,12 @@ def button_link():
|
|
|
|
global button
|
|
|
|
global button
|
|
|
|
# 替每个主界面的按钮绑定各自的函数
|
|
|
|
# 替每个主界面的按钮绑定各自的函数
|
|
|
|
button['button1'].config(command=train_setting)
|
|
|
|
button['button1'].config(command=train_setting)
|
|
|
|
button['button2'].config(command=train)
|
|
|
|
button['button2'].config(command=train) # 训练
|
|
|
|
button['button3'].config(command=model_show)
|
|
|
|
button['button3'].config(command=model_show) # 训练
|
|
|
|
button['button4'].config(command=load_model)
|
|
|
|
button['button4'].config(command=load_model) # 训练
|
|
|
|
button['button5'].config(command=restart_new_model)
|
|
|
|
button['button5'].config(command=restart_new_model) # 训练
|
|
|
|
button['button6'].config(command=setpara_func)
|
|
|
|
button['button6'].config(command=setpara_func) # 训练
|
|
|
|
button['button7'].config(command=save_model)
|
|
|
|
button['button7'].config(command=save_model) # 保存模型
|
|
|
|
button['button8'].config(command=check_connection)
|
|
|
|
button['button8'].config(command=check_connection)
|
|
|
|
button['button9'].config(command=close_program)
|
|
|
|
button['button9'].config(command=close_program)
|
|
|
|
|
|
|
|
|
|
|
@ -1953,10 +1889,10 @@ def main():
|
|
|
|
global button
|
|
|
|
global button
|
|
|
|
Root = tk.Tk()
|
|
|
|
Root = tk.Tk()
|
|
|
|
# 设置窗口的大小为1200*750
|
|
|
|
# 设置窗口的大小为1200*750
|
|
|
|
window_width = 1200 # 窗口的宽度
|
|
|
|
window_width = 800 # 窗口的宽度
|
|
|
|
window_height = 750 # 窗口的高度
|
|
|
|
window_height = 450 # 窗口的高度
|
|
|
|
Root.title("神经网络可视化")
|
|
|
|
Root.title("神经网络可视化")
|
|
|
|
Root.geometry("1200x750") # 设置窗口的大小和位置
|
|
|
|
Root.geometry("800x450") # 设置窗口的大小和位置
|
|
|
|
picture_frame(window_width, window_height)
|
|
|
|
picture_frame(window_width, window_height)
|
|
|
|
Listinstance = create_instance()
|
|
|
|
Listinstance = create_instance()
|
|
|
|
# 创建网络对象总表和网络连接对象总表
|
|
|
|
# 创建网络对象总表和网络连接对象总表
|
|
|
@ -1974,4 +1910,4 @@ def main():
|
|
|
|
sys.stdout.write = redirector
|
|
|
|
sys.stdout.write = redirector
|
|
|
|
Root.mainloop()
|
|
|
|
Root.mainloop()
|
|
|
|
if __name__ == '__main__':
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|
|
|
|
main()
|