更新代码

master
bettleChen 11 months ago
parent 60821df10a
commit b2eb7b808b

BIN
2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

File diff suppressed because it is too large Load Diff

249
X1.py

@ -18,6 +18,253 @@
SetParaFunc为给基本操作函数赋参数值的函数ParaString 为同类不同图元的参数ObjX,
ObjY为对象在仿真输出屏幕中的位置示例中未给出由图形界面中的位置产生
'''
class ModelObj: # 网络对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
self.ObjID = ObjID # 图元号
self.ObjType = ObjType # 图元类别
self.ObjLable = ObjLable # 对象标签
self.ParaString = ParaString # 参数字符串
self.ObjX = ObjX # 对象位置x坐标
self.ObjY = ObjY # 对象位置y坐标
class Data_Class(ModelObj): # 数据集网络对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.LoadData = self.load_data # 基本操作函数
self.SetDataPara = self.set_data_para # 参数设置函数
def load_data(self, DataPara):
pass # X3具体实现
def set_data_para(self):
pass # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.LoadData,
self.SetDataPara, self.ParaString, self.ObjX, self.ObjY]
return result
# if __name__ == '__main__':
# DataSet = Data_Class("DataSet1", 1, "数据集1", ".", 120, 330)
# print(DataSet)
class Conv_Class(ModelObj): # 卷积对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.ConvProc = self.conv_proc # 基本操作函数
self.SetConvPara = self.setconv_para # 参数设置函数
def conv_proc(self, image, ConvPara):
pass # X3具体实现
def setconv_para(self):
pass # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.ConvProc, self.SetConvPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class Pool_Class(ModelObj): # 池化对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.MaxPoolProc = self.pool_proc # 基本操作函数
self.SetPollPara = self.setpool_para # 参数设置函数
def pool_proc(self, image, PoolPara):
pass # X3具体实现
def setpool_para(self):
pass # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.MaxPoolProc, self.SetPollPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class FullConn_Class(ModelObj): # 全连接对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.FullConnProc = self.fullconn_proc # 基本操作函数
self.SetFullConnPara = self.setfullconn_para # 参数设置函数
def fullconn_proc(self, inputdata, FullConnPara):
pass # X3具体实现
def setfullconn_para(self, data):
pass # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.FullConnProc, self.SetFullConnPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class Nonline_Class(ModelObj): # 非线性对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.NonlinearProc = self.nonlinear_proc # 基本操作函数
self.SetNonLPara = self.setnonl_para # 参数设置函数
def nonlinear_proc(self, inputdata, NonLPara):
pass # X3具体实现
def setnonl_para(self):
pass # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.NonlinearProc, self.SetNonLPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class Classifier_Class(ModelObj): # 分类对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.ClassifierProc = self.classifier_proc # 基本操作函数
self.SetClassifyPara = self.setclassify_para # 参数设置函数
def classifier_proc(self, inputdata, ClassifyPara):
pass # X3具体实现
def setclassify_para(self):
pass # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.ClassifierProc, self.SetClassifyPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class Error_Class(ModelObj): # 误差计算对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.ErrorProc = self.error_proc # 基本操作函数
self.SetErrorPara = self.seterror_para # 参数设置函数
def error_proc(self, input, label, ErrorPara):
pass # X3具体实现
def seterror_para(self):
pass # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.ErrorProc, self.SetErrorPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class AjConv_Class(ModelObj): # 卷积调整对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.AjConvProc = self.ajconv_proc # 基本操作函数
self.SetAjConvPara = self.setajconv_para # 参数设置函数
def ajconv_proc(self, input, AjConvPara):
pass # X3具体实现
def setajconv_para(self):
pass # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.AjConvProc, self.SetAjConvPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class AjFullconn_Class(ModelObj): # 全连接调整对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.AjFullconnProc = self.ajfullconn_proc # 基本操作函数
self.SetAjFCPara = self.setajfc_para # 参数设置函数
def ajfullconn_proc(self):
pass # X3具体实现
def setajfc_para(self, AjFCPara):
print(AjFCPara) # X3具体实现
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.AjFullconnProc, self.SetAjFCPara, self.ParaString, self.ObjX,
self.ObjY]
return result
# AjFullconn = AjFullconn_Class("AjFullconn", 9,
# "全连接调整1", [], 510, 120)
# AjFullconn.SetAjFCPara('rrr')
DataSet = Data_Class("DataSet1", 1, "数据集1", [], 120, 330).output()
Conv = Conv_Class("Conv1", 2, "卷积1", [], 250, 330).output()
Pool = Pool_Class("Pool1", 3, "最大池化1", [], 380, 330).output()
FullConn = FullConn_Class("FullConn1", 4, "全连接1", [], 510, 330).output()
Nonline = Nonline_Class("Nonline1", 5, "非线性函数1", [], 640, 330).output()
Classifier = Classifier_Class("Classifier1", 6, "分类1", [], 780, 330).output()
Error = Error_Class("Error1", 7, "误差计算1", [], 710, 124).output()
AjConv = AjConv_Class("AjConv1", 8, "卷积调整1", [], 250, 70).output()
AjFullconn = AjFullconn_Class("AjFullconn1", 9,
"全连接调整1", [], 510, 120).output()
AllModelObj = [DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn]
# AjFullconn.SetAjFCPara(7)
# AjFullconn.SetAjFCPara(7)
# print(AllModelObj)
# 定义网络连接对象类
class ModelConn:
def __init__(self, ConnObjID, ConnType, NobjS, NobjE):
self.ConnObjID = ConnObjID # 连接线编号
self.ConnType = ConnType # 连接线类别
self.NobjS = NobjS # 源图元对象
self.NobjE = NobjE # 目标图元对象
def output(self): # 输出方法
# 创建一个空列表
result = [self.ConnObjID, self.ConnType, self.NobjS, self.NobjE]
return result
# if __name__ == '__main__':
# ···AllModelObj方法继承
# # 创建连接对象实例
# Line1 = ModelConn(1, 1, DataSet.ObjID, Conv.ObjID)
# Line2 = ModelConn(2, 1, Conv.ObjID, Pool.ObjID)
# Line3 = ModelConn(3, 1, Pool.ObjID, FullConn.ObjID)
# Line4 = ModelConn(4, 1, FullConn.ObjID, Nonline.ObjID)
# Line5 = ModelConn(5, 1, Nonline.ObjID, Classifier.ObjID)
# Line6 = ModelConn(6, 1, Classifier.ObjID, Error.ObjID)
# Line7 = ModelConn(7, 2, Error.ObjID, AjFullconn.ObjID)
# Line8 = ModelConn(8, 2, Error.ObjID, AjConv.ObjID)
# Line9 = ModelConn(9, 2, AjFullconn.ObjID, FullConn.ObjID)
# Line10 = ModelConn(10, 2, AjConv.ObjID, Conv.ObjID)
#
# # 网络连接对象总表
# AllModelConn = [[Line1], [Line2], [Line3], [Line4],
# [Line5], [Line6], [Line7], [Line8],
# [Line9], [Line10]]
# print(AllModelConn)
# X16.1赋值
AllModelObj = [
['DataSet1', 1, '数据集1', 'LoadData',
'SetDataPara', [], 120, 330],
['Conv1', 2, '卷积1', 'ConvProc',
'SetConvPara', [], 250, 330],
['Pool1', 3, '最大池化1', 'MaxPoolProc',
'SetPollPara', [], 380, 330],
['FullConn1',4,'全连接1','FullConnProc',
'SetFullConnPara', [], 510,330],
['Nonline1',5,'非线性函数1', 'NonlinearProc',
'SetNonLPara', [], 640, 330],
['Classifier1',6,'分类1','ClassifierProc',
'SetClassifyPara',[],780,330],
['Error1', 7, '误差计算1', 'ErrorProc',
'SetErrorPara', [], 710, 124],
['AjConv1', 8, '卷积调整1', 'AjConvProc',
'SetAjConvPara', [], 250, 70],
['AjFullconn1',9,'全连接调整1','AjFullconnProc',
'SetAjFCPara',[],510,120]]
AllModelConn = [
[1, 1, 'DataSet1', 'Conv1'], [2, 1, 'Conv1', 'Pool1'],
[3, 1, 'Pool1', 'FullConn1'], [4, 1, 'FullConn1', 'Nonline1'],
[5, 1, 'Nonline1', 'Classifier1'], [6, 1, 'Classifier1', 'Error1'],
[7, 2, 'Error1', 'AjFullconn1'], [8, 2, 'Error1', 'AjConv1'],
[9, 2, 'AjFullconn1', 'FullConn1'], [10, 2, 'AjConv1', 'Conv1']]
# 定义一个函数根据给定的参数生成一个AllModelObj对象
def create_almodelobj():
@ -43,6 +290,7 @@ def create_almodelobj():
all_model.append(obj)
return all_model
# if __name__ == '__main__':
# all_model = create_almodelobj()
# print(all_model)
@ -68,6 +316,7 @@ def create_allmodelconn():
for i in range(len(conn_obj_id)) # 循环遍历连接线编号的长度
]
return all_conn
# print(create_allmodelconn())
# if __name__ == '__main__':
# all_conn = create_allmodelconn()

@ -0,0 +1,136 @@
import tkinter as tk
from PIL import Image, ImageTk
from X1 import *
global Viewcanvas # 定义画布
global Root # 主窗口
global AllModelObj #网络对象
'''
编程16.5编制程序依据AllModelObj和AllModelConn数据结构产生如图16.2的输出界面
目的及编程说明读者通过编程16.5可理解卷积神经网络模型构建的输出界面数据结构及初始值参见编程16.1
'''
def create_instance():
global AllModelObj
global DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn
DataSet = Data_Class("DataSet1", 1, "数据集1", ".", 120, 330)
Conv = Conv_Class("Conv1", 2, "卷积1", ".", 250, 330)
Pool = Pool_Class("Pool1", 3, "最大池化1", ".", 380, 330)
FullConn = FullConn_Class("FullConn1", 4, "全连接1", ".", 510, 330)
Nonline = Nonline_Class("Nonline1", 5, "非线性函数1", ".", 640, 330)
Classifier = Classifier_Class("Classifier1", 6, "分类1", ".", 780, 330)
Error = Error_Class("Error1", 7, "误差计算1", ".", 710, 124)
AjConv = AjConv_Class("AjConv1", 8, "卷积调整1", ".", 250, 70)
AjFullconn = AjFullconn_Class("AjFullconn1", 9, "全连接调整1", ".", 510, 120)
AllModelObj = [DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn]
def connect_class():
global AllModelConn
# 创建连接对象实例
Line1 = ModelConn(1, 1, DataSet.ObjID, Conv.ObjID).output()
Line2 = ModelConn(2, 1, Conv.ObjID, Pool.ObjID).output()
Line3 = ModelConn(3, 1, Pool.ObjID, FullConn.ObjID).output()
Line4 = ModelConn(4, 1, FullConn.ObjID, Nonline.ObjID).output()
Line5 = ModelConn(5, 1, Nonline.ObjID, Classifier.ObjID).output()
Line6 = ModelConn(6, 1, Classifier.ObjID, Error.ObjID).output()
Line7 = ModelConn(7, 2, Error.ObjID, AjFullconn.ObjID).output()
Line8 = ModelConn(8, 2, Error.ObjID, AjConv.ObjID).output()
Line9 = ModelConn(9, 2, AjFullconn.ObjID, FullConn.ObjID).output()
Line10 = ModelConn(10, 2, AjConv.ObjID, Conv.ObjID).output()
# 网络连接对象总表
AllModelConn = [Line1, Line2, Line3, Line4,
Line5, Line6, Line7, Line8,
Line9, Line10]
def element(path):
img = Image.open(path) # 加载图元对应的图片文件
img = img.resize((60, 50)) # 使用resize方法调整图片
img = ImageTk.PhotoImage(img) # 把Image对象转换成PhotoImage对象
Root.img = img # 保存图片的引用,防止被垃圾回收
return img
def window():
global Root
global Viewcanvas
Root = tk.Tk() # 创建一个主窗口
# 设置窗口的大小为1200*750
window_width = 900 # 窗口的宽度
window_height = 550 # 窗口的高度
Root.title("神经网络可视化")
Root.geometry("900x550") # 设置窗口的大小和位置
# 创建一个画布,用于绘制矩形框,设置画布的大小和背景色
Viewcanvas = tk.Canvas(Root, width=window_width, height=window_height, bg="white")
# 将画布添加到主窗口中
Viewcanvas.pack()
# 绘制矩形框,使用不同的颜色和线宽,指定矩形框的左上角和右下角坐标,填充色,边框色和边框宽度
Viewcanvas.create_rectangle(5, 5, 895, 545, fill=None, outline="lightblue", width=2)
def connecting_lines(obj_x, obj_y, text, text_record,image):
Viewcanvas.create_image(obj_x, obj_y, image=image) # 创建图元对象
Viewcanvas.create_text(obj_x + text_record[0], obj_y + text_record[1], text=text, font=("黑体", 14)) # 创建图元对象的标签
def conn_lines(start, end, index):
smooth = [False, True]
width = [2, 4]
if start[0] == end[0]:
Viewcanvas.create_line(start[0], start[1] + 30, end[0] , end[1] - 30, arrow=tk.LAST,
arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth[index], width=width[index])
elif start[1] == end[1]:
Viewcanvas.create_line(start[0] + 30, start[1], end[0] - 30, end[1], arrow=tk.LAST,
arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth[index], width=width[index])
else:
if abs(start[0]-end[0]) > abs(start[1]-end[1]):
# 创建数据线箭头
Viewcanvas.create_line(start[0]-15, start[1], int((start[0] + end[0])/2), end[1], end[0] + 30, end[1], arrow=tk.LAST,
arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth[index], width=width[index])
else:
# 创建数据线箭头
Viewcanvas.create_line(start[0], start[1] - 20, start[0], end[1], end[0] + 30, end[1], arrow=tk.LAST, arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth[index], width=width[index])
def creating_elements():
text_record = [(0, -50), (0, 50), (-80, 0)]
# 遍历AllModelObj列表在窗口左侧创建图元菜单
for obj in AllModelObj:
# 并且要根据需求调整每个对象的位置
obj_x = obj.ObjX # 根据对象的id计算x坐标
obj_y = obj.ObjY # 根据对象的id计算y坐标
Item_Record.append((obj_x, obj_y))
Item_Name.append(obj.ObjID)
# 根据对象的类型,绘制相应的图形
if 'Error' in obj.ObjID:
connecting_lines(obj_x, obj_y, obj.ObjLable, text_record[0], list_image[obj.ObjType - 1])
elif 'Aj' in obj.ObjID:
connecting_lines(obj_x, obj_y, obj.ObjLable, text_record[2], list_image[-1])
else:
connecting_lines(obj_x, obj_y, obj.ObjLable, text_record[1], list_image[obj.ObjType - 1])
def ligature(): # 连接线
# print(Item_Record)
for conn in AllModelConn:
starting = Item_Name.index(conn[2])
# print(starting)
ending = Item_Name.index(conn[3])
if conn[1] == 1:
# print(Item_Record[starting])
conn_lines(Item_Record[starting], Item_Record[ending], 1)
else:
conn_lines(Item_Record[starting], Item_Record[ending], 0)
if __name__ == '__main__':
global AllModelObj
Item_Record = []
Item_Name = []
window()
create_instance()
connect_class()
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"]
list_image = []
for path in img_path:
list_image.append(element(path))
creating_elements()
ligature()
Root.mainloop()
# print(Item_Record)

@ -0,0 +1,128 @@
import tkinter as tk
from PIL import Image, ImageTk
from X1 import *
def create_instance():
global AllModelObj
global DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn
DataSet = Data_Class("DataSet1", 1, "数据集1", ".", 120, 330)
Conv = Conv_Class("Conv1", 2, "卷积1", ".", 250, 330)
Pool = Pool_Class("Pool1", 3, "最大池化1", ".", 380, 330)
FullConn = FullConn_Class("FullConn1", 4, "全连接1", ".", 510, 330)
Nonline = Nonline_Class("Nonline1", 5, "非线性函数1", ".", 640, 330)
Classifier = Classifier_Class("Classifier1", 6, "分类1", ".", 780, 330)
Error = Error_Class("Error1", 7, "误差计算1", ".", 710, 124)
AjConv = AjConv_Class("AjConv1", 8, "卷积调整1", ".", 250, 70)
AjFullconn = AjFullconn_Class("AjFullconn1", 9, "全连接调整1", ".", 510, 120)
AllModelObj = [DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn]
def connect_class():
global AllModelConn
# 创建连接对象实例
Line1 = ModelConn(1, 1, DataSet.ObjID, Conv.ObjID).output()
Line2 = ModelConn(2, 1, Conv.ObjID, Pool.ObjID).output()
Line3 = ModelConn(3, 1, Pool.ObjID, FullConn.ObjID).output()
Line4 = ModelConn(4, 1, FullConn.ObjID, Nonline.ObjID).output()
Line5 = ModelConn(5, 1, Nonline.ObjID, Classifier.ObjID).output()
Line6 = ModelConn(6, 1, Classifier.ObjID, Error.ObjID).output()
Line7 = ModelConn(7, 2, Error.ObjID, AjFullconn.ObjID).output()
Line8 = ModelConn(8, 2, Error.ObjID, AjConv.ObjID).output()
Line9 = ModelConn(9, 2, AjFullconn.ObjID, FullConn.ObjID).output()
Line10 = ModelConn(10, 2, AjConv.ObjID, Conv.ObjID).output()
# 网络连接对象总表
AllModelConn = [Line1, Line2, Line3, Line4,
Line5, Line6, Line7, Line8,
Line9, Line10]
class Networking:
def __init__(self):
self.Root = tk.Tk() # 创建一个主窗口
# 设置窗口的大小为1200*750
self.window_width = 900 # 窗口的宽度
self.window_height = 550 # 窗口的高度
self.list_image = []
self.Item_Record = [[], []] # 记录图元坐标与图元号
def window(self):
self.Root.title("神经网络可视化")
self.Root.geometry("900x550") # 设置窗口的大小和位置
# 创建一个画布,用于绘制矩形框,设置画布的大小和背景色
self.Viewcanvas = tk.Canvas(self.Root, width=self.window_width, height=self.window_height, bg="white")
# 将画布添加到主窗口中
self.Viewcanvas.pack()
# 绘制矩形框,使用不同的颜色和线宽,指定矩形框的左上角和右下角坐标,填充色,边框色和边框宽度
self.Viewcanvas.create_rectangle(5, 5, 895, 545, fill=None, outline="lightblue", width=2)
def connecting_lines(self, obj):
obj_x = obj.ObjX # 根据对象的id计算x坐标
obj_y = obj.ObjY # 根据对象的id计算y坐标
text = obj.ObjLable
if 'Error' in obj.ObjID:
x, y = 0, -50
elif 'Aj' in obj.ObjID:
x, y = -80, 0
else:
x, y = 0, 50
self.Viewcanvas.create_image(obj_x, obj_y, image=self.list_image[obj.ObjType - 1]) # 创建图元对象
self.Viewcanvas.create_text(obj_x + x, obj_y + y, text=text, font=("黑体", 14)) # 创建图元对象的标签
def conn_lines(self, conn):
starting = self.Item_Record[1].index(conn[2])
ending = self.Item_Record[1].index(conn[3])
smooth = [False, True]
width = [2, 4]
start, end = self.Item_Record[0][starting], self.Item_Record[0][ending]
index = 1 if conn[1] == 1 else 0
if start[0] == end[0]:
self.Viewcanvas.create_line(start[0], start[1] + 30, end[0], end[1] - 30, arrow=tk.LAST,
arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth[index], width=width[index])
elif start[1] == end[1]:
self.Viewcanvas.create_line(start[0] + 30, start[1], end[0] - 30, end[1], arrow=tk.LAST,
arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth[index], width=width[index])
else:
if abs(start[0] - end[0]) > abs(start[1] - end[1]):
# 创建数据线箭头
self.Viewcanvas.create_line(start[0] - 15, start[1], int((start[0] + end[0]) / 2), end[1], end[0] + 30,
end[1], arrow=tk.LAST,
arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth[index],
width=width[index])
else:
# 创建数据线箭头
self.Viewcanvas.create_line(start[0], start[1] - 20, start[0], end[1], end[0] + 30, end[1], arrow=tk.LAST,
arrowshape=(16, 20, 4), fill='lightblue', smooth=smooth[index],
width=width[index])
def creating_elements(self):
text_record = [(0, -50), (0, 50), (-80, 0)]
# 遍历AllModelObj列表在窗口左侧创建图元菜单
for obj in self.AllModelObj:
# 并且要根据需求调整每个对象的位置
obj_x = obj.ObjX # 根据对象的id计算x坐标
obj_y = obj.ObjY # 根据对象的id计算y坐标
self.Item_Record.append((obj_x, obj_y))
self.connecting_lines(obj,)
def element(self, path):
img = Image.open(path) # 加载图元对应的图片文件
img = img.resize((60, 50)) # 使用resize方法调整图片
img = ImageTk.PhotoImage(img) # 把Image对象转换成PhotoImage对象
self.Root.img = img # 保存图片的引用,防止被垃圾回收
return img
def read_element(self):
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/adjust.png"]
for path in img_path:
self.list_image.append(self.element(path))
def visual_output(self, AllModelObj, AllModelConn):
for obj in AllModelObj: # 遍历AllModelObj列表在窗口创建图元
self.Item_Record[0].append((obj.ObjX, obj.ObjY)) # 记录图元坐标
self.Item_Record[1].append(obj.ObjID) # 记录图元号
self.connecting_lines(obj) # 根据图元对象信息在画布上画图元
for conn in AllModelConn: # 遍历AllModelConn列表在窗口连线图元
self.conn_lines(conn)
if __name__ == '__main__':
create_instance()
connect_class()
Net = Networking()
Net.window()
Net.read_element()
Net.visual_output(AllModelObj, AllModelConn)
Net.Root.mainloop()

121
X3.py

@ -1,4 +1,5 @@
import os
import cv2
import numpy as np
import tkinter as tk
from tkinter import filedialog
@ -52,13 +53,20 @@ def setload_data(): # 定义加载数据集的参数SetLoadData()
def load_data(DataPara):
imgPaths=["train_imgPath","test_imgPath"] # DataPara的键名
listimages=[] # 存储图片的列表
list_path = []
for datapath in imgPaths:
filenames = os.listdir(DataPara[datapath])
images = [] # 存储图片的列表
Path = []
for tfname in filenames:
if os.path.isdir(tfname) == False: # 如果不是子文件夹,就是图片文件
path = DataPara[datapath] + tfname # 拼接图片路径
# 引用X1里面的image_to_array()方法
path = os.path.join(DataPara[datapath], tfname) # 使用os.path.join()拼接图片路径
Path.append(path)
file_paths = sorted(Path, key=lambda x: int(x.split("/")[-1].split(".")[0]))
list_path.append(file_paths)
for data_path in list_path:
images = [] # 存储图片的列表
for path in data_path:
# print(path)
img = image_to_array(path, DataPara["img_width"], DataPara["img_height"]) # 读取图片数据
img = img.T # 转置,图像的行和列将互换位置。
images.append(img) # 将图片数组添加到训练集图片列表中
@ -118,7 +126,6 @@ def conv_proc(image, ConvPara): # 定义卷积函数ConvProc()
for j in range(out_w):
stride = ConvPara["stride"] # 获得步长
output[k, i, j] = np.sum(image[k, i * stride:i * stride + 3, j * stride:j * stride + 3] * kernel)# 计算卷积操作
return output # 返回卷积计算后的数组(特征向量)
# if __name__ == '__main__':
@ -382,7 +389,6 @@ def classify(nonlinear_images):
output = classifier_proc(image, ClassifyPara) # 进行分类处理
classifier_images.append(output) # 将分类结果存储到列表
classifier_images = np.array(classifier_images) # 将分类的结果列表转换为数组形式,方便后续处理
print(classifier_images)
return classifier_images, prob_images
'''
编程16.12编制程序设置标签类别SetLabelPara()及为样本标记标签函数LabelProc()
@ -474,7 +480,7 @@ def loss_count(prob_images):
input = prob_images # print(len(input))
array = np.arange(1, 11) # 定义一个一维数组包含1到10的整数
# 从a中随机抽取100个元素有放回每个元素的概率相同
right_label = np.random.choice(array, DataPara['batch_size'])
right_label = np.random.choice(array, 900)
loss = error_proc(input, right_label, ErrorPara) # 计算误差值
return loss
@ -486,41 +492,27 @@ SetAjConvPara()实现的具体要求为:1确定卷积调整的参数
2返回参数AjConvPara4.028404024493524
AjConvProc()的具体实现要求为1使用误差值计算卷积层的误差项和梯度2梯度下降算法更新卷积层参数3返回新的卷积层参数
'''
def conv_ajconv(loss,images):
global ConvPara
kernel = ConvPara["kernel"]
bias = 0.5
loss = np.array([[loss]])
new_kernel, new_bias = ajconv_proc(images, kernel, bias, loss)
ConvPara["kernel"] = new_kernel
ConvPara["bias"] = new_bias
print('卷积参数更新后的卷积核:')
print(new_kernel)
print('卷积参数更新后的偏置向量:')
print(new_bias)
def ajconv_proc(input, kernel, bias, loss):
kernel_grad_list = []
bias_grad = 0 # 初始化偏置项梯度为零
def setajconv_para():
kernel = np.array([[1.0,2.0],[3.0,4.0]]) # 卷积核信息
learning_rate = 0.01 # 学习率
bias = 0.5 # 偏置
loss = np.array([[0.1, 0.2], [0.3, 0.4]])
AjConvPara={'kernel_info': kernel,'learning_rate': learning_rate,'bias': bias,'loss': loss}
return AjConvPara
def ajconv_proc(input, AjConvPara):
k = [] # 计算卷积核和偏置项的梯度
bias_grad = np.sum(AjConvPara['loss']) # 计算偏置项梯度为误差值之和
for c in input:
# 计算卷积核和偏置项的梯度
kernel_grad = np.zeros_like(kernel) # 初始化卷积核梯度为零矩阵
for i in range(loss.shape[0]): # 遍历误差值矩阵的行
for j in range(loss.shape[1]): # 遍历误差值矩阵的列
# 将输入数据数组中对应的子矩阵旋转180度与误差值相乘累加到卷积核梯度上
kernel_grad += np.rot90(c[i:i + kernel_grad.shape[0], j:j + kernel_grad.shape[0]], 2) * loss[i, j]
# 将误差值累加到偏置项梯度上
bias_grad += loss[i, j]
kernel_grad_list.append(kernel_grad)
# 使用stack函数沿着第0个轴把一百个a数组堆叠起来
result = np.stack(kernel_grad_list, axis=0)
kernel_grad = np.sum(result, axis=0) / len(input) # 沿着第0个维度求和
# 设置学习率为0.01
learning_rate = 0.01
# 更新卷积核和偏置项参数
kernel = kernel - learning_rate * kernel_grad # 卷积核参数减去学习率乘以卷积核梯度
bias = bias - learning_rate * bias_grad # 偏置项参数减去学习率乘以偏置项梯度
# 返回更新后的卷积核、偏置
return kernel, bias
kernel_grad = np.zeros_like(AjConvPara['kernel_info']) # 初始化卷积核梯度为零矩阵
for i in range(AjConvPara['loss'].shape[0]): # 遍历误差值矩阵的每一行
for j in range(AjConvPara['loss'].shape[1]): # 遍历误差值矩阵的每一列
kernel_grad += np.rot90(c[i:i + 2, j:j + 2], 2) * AjConvPara['loss'][i, j]
k.append(kernel_grad)
result = np.stack(k, axis=0)
kernel_grad = np.sum(result, axis=0) / len(input)
kernel = AjConvPara['kernel_info'] - AjConvPara['learning_rate'] * kernel_grad
bias = AjConvPara['bias'] - AjConvPara['learning_rate'] * bias_grad
return kernel, bias# 返回更新后的卷积核和偏置项
# if __name__ == '__main__':
# input = np.array([[[1,2,3],[4,5,6],[7,8,9]],
# [[10,11,12],[13,14,15],[16,17,18]],
@ -531,29 +523,24 @@ def ajconv_proc(input, kernel, bias, loss):
# print("\nkernel_new =\n", kernel_new,"\n")
# print("bias_new =", bias_new)
# 定义一个全连接层的权重矩阵和偏置向量的调整函数,可以选择不同的激活函数
def update_parameters(weight_matrix, bias_vector, loss):
# 根据激活函数的参数选择相应的函数和导数
# 计算权重矩阵和偏置向量的梯度,使用链式法则
learning_rate = 0.01
gradient_weights = np.outer(loss, learning_rate)
# 更新权重矩阵和偏置向量
weight_matrix = weight_matrix - gradient_weights
bias_vector = bias_vector - learning_rate * bias_vector
# 返回更新后的权重矩阵和偏置向量
return weight_matrix, bias_vector
def ajfullconn_proc(loss):
global FullConnPara
weight1 = FullConnPara["weights"]
bias1 = FullConnPara["bias"]
loss = np.array([loss])
new_weight1, new_bias1 = update_parameters(weight1, bias1, loss)
FullConnPara["weights"] = new_weight1
FullConnPara["bias"] = new_bias1
print('全连接参数更新后的权重矩阵:')
print(new_weight1)
print('全连接参数更新后的偏置向量:')
print(new_bias1)
def setajfc_para():
AjFCPara = {
'weights': np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]]), # 全连接权重
'bias': np.array([0.5, 0.6]), # 全连接偏置
'learning_rate': 0.01, # 学习率
'error': np.array([0.001, 0.002]) # 误差值
}
return AjFCPara
def ajfullconn_proc(AjFCPara):
error_value = AjFCPara['error']
learning_rate = AjFCPara['learning_rate']
error_term = error_value # 全连接层的误差项等于误差值
gradient_weights = np.outer(error_term, learning_rate) # 计算权重梯度
gradient_bias = error_term * learning_rate # 计算偏置梯度
# 更新全连接层参数(梯度下降算法)
AjFCPara['weights'] -= gradient_weights
AjFCPara['bias'] -= gradient_bias
return AjFCPara
# if __name__ == '__main__':
# AjFCPara = setajfc_para()# 调用SetAjFCPara()设置参数
# print("初始化的全连接层参数:", AjFCPara)
@ -581,9 +568,7 @@ def main():
parameter()
global DataPara
train_images, test_images = load_data(DataPara) # 调用LoadData()函数,根据参数加载数据集
for i in range(len(train_images) // DataPara['batch_size']):
train_image=train_images[i * DataPara['batch_size']:(i + 1) * DataPara['batch_size']]
conv_images = convolutional_operation(train_image) # 存储卷积处理后的图片的列表
conv_images = convolutional_operation(train_images) # 存储卷积处理后的图片的列表
pool_images = pooling_treatment(conv_images) # 存储还回池化处理后的图片的列表
global FullConnPara
FullConnPara = setfullconn_para(pool_images[0]) # 调用设置全连接层参数的函数,获取全连接参数
@ -593,9 +578,7 @@ def main():
labeled_samples = label_proc(nonlinear_images, prob_images, classifier_images) # 读取之前的分类,每一行是一个样本,每一列是一个特征,将分类标签放在最后一列
loss = loss_count(prob_images)
# 打印结果
print('loss值{}'.format(loss))
conv_ajconv(loss,train_image)
ajfullconn_proc(loss)
print(loss)
if __name__ == '__main__':
main()

@ -0,0 +1,485 @@
import os
import cv2
import numpy as np
import tkinter as tk
from tkinter import filedialog
from read_data import *
from PIL import Image
class ModelObj: # 网络对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
self.ObjID = ObjID # 图元号
self.ObjType = ObjType # 图元类别
self.ObjLable = ObjLable # 对象标签
self.ParaString = ParaString # 参数字符串
self.ObjX = ObjX # 对象位置x坐标
self.ObjY = ObjY # 对象位置y坐标
class Data_Class(ModelObj): # 数据集网络对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.LoadData = self.load_data # 基本操作函数
self.SetDataPara = self.set_data_para # 参数设置函数
# 定义加载数据集load_data()
def load_data(self, DataPara):
global SubFolders
listimages = [] # 存储图片的列表
list_path = []
SubFolders, train_Path = read_folders(DataPara["train_imgPath"])
list_path.append(train_Path)
_, path_list = read_folders(DataPara["test_imgPath"])
list_path.append(path_list)
for data_path in list_path:
images = [] # 存储图片的列表
for path in data_path:
# print(path)
img = self.image_to_array(path, DataPara["img_width"], DataPara["img_height"]) # 读取图片数据
img = img.T # 转置,图像的行和列将互换位置。
images.append(img) # 将图片数组添加到训练集图片列表中
listimages.append(np.array(images)) # 返回转换后的数组
return listimages[0], listimages[1]
def set_data_para(self):# 定义加载数据集的参数SetLoadData()
# 设置数据集路径信息
train_imgPath = 'data_classification/train/' # 训练集文件夹的位置
test_imgPath = 'data_classification/test/' # 测试集文件夹的位置
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 image_to_array(self, path, height, width):
img = Image.open(path).convert("L") # 转换为灰度模式
img = img.resize((height, width)) # 将图片缩放为height*width的固定大小
data = np.array(img) # 将图片转换为数组格式
data = data / 255.0 # 将数组中的数值归一化除以255
return data
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.LoadData,
self.SetDataPara, self.ParaString, self.ObjX, self.ObjY]
return result
# if __name__ == '__main__':
# DataSet = Data_Class("DataSet1", 1, "数据集1", ".", 120, 330)
# print(DataSet)
class Conv_Class(ModelObj): # 卷积对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.ConvProc = self.conv_proc # 基本操作函数
self.SetConvPara = self.setconv_para # 参数设置函数
# 定义卷积函数ConvProc()
def conv_proc(self, image, ConvPara):
# 获取输入数据的大小,这里假设是单通道的图片
c, image_h, image_w = image.shape
kernel_h = ConvPara["kernel_h"] # 获取卷积核的大小和卷积核
kernel_w = ConvPara["kernel_w"]
kernel = ConvPara["kernel"]
out_h = (image_h - kernel_h) // ConvPara["stride"] + 1 # 计算输出数据的大小
out_w = (image_w - kernel_w) // ConvPara["stride"] + 1
output = np.zeros((c, out_h, out_w)) # 初始化输出数据为零矩阵
for k in range(c): # 遍历每个通道
for i in range(out_h): # 遍历每个输出位置
for j in range(out_w):
stride = ConvPara["stride"] # 获得步长
output[k, i, j] = np.sum(
image[k, i * stride:i * stride + 3, j * stride:j * stride + 3] * kernel) # 计算卷积操作
return output # 返回卷积计算后的数组(特征向量)
def setconv_para(self):# 定义设置卷积参数的函数SetConvPara()
kernel_h = 3 # 设置卷积核大小这里假设是3x3
kernel_w = 3
kernel = [[1.289202, -1.471377, -0.238452], # 卷积核为3x3的单位矩阵(高斯分布)
[-0.562343, -0.019988, -0.441446],
[1.627381, 1.390266, 0.812486]]
stride = 1 # 设置步长这里假设是1
padding = 0 # 设置填充这里假设是0
ConvPara = {"kernel": kernel, # 返回ConvPara参数这里用一个字典来存储
"kernel_h": kernel_h,
"kernel_w": kernel_w,
"stride": stride,
"padding": padding}
return ConvPara
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.ConvProc, self.SetConvPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class Pool_Class(ModelObj): # 池化对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.MaxPoolProc = self.pool_proc # 基本操作函数
self.SetPollPara = self.setpool_para # 参数设置函数
def pool_proc(self, image, PoolPara):
pool_mode = PoolPara["pool_mode"]
pool_size = PoolPara["pool_size"]
stride = PoolPara["stride"]
c, h, w = image.shape # 获取输入特征图的高度和宽度
out_h = int((h - pool_size) / stride) + 1 # 计算输出特征图的高度
out_w = int((w - pool_size) / stride) + 1 # 计算输出特征图的宽度
out = np.zeros((c, out_h, out_w)) # 初始化输出特征图为全零数组
for k in range(c): # 对于输出的每一个位置上计算:
for i in range(out_h):
for j in range(out_w):
window = image[k, i * stride:i * stride + pool_size, j * stride:j * stride + pool_size]
if pool_mode == "max": # 最大池化
out[k][i][j] = np.max(window)
elif pool_mode == "avg": # 平均池化
out[k][i][j] = np.mean(window)
elif pool_mode == "min": # 最小池化
out[k][i][j] = np.min(window)
else: # 无效的池化类型
raise ValueError("Invalid pooling mode")
return out # 返回特征图。
# 定义设置池化参数的函数
def setpool_para(self):
pool_mode = "max" # 设置池大小和池类型这里假设是2x2最大池化
pool_size = 2
stride = 2 # 设置步长这里假设是2
PoolPara = {"pool_mode": pool_mode, "pool_size": pool_size, "stride": stride} # 返回PoolPara参数这里用一个字典来存储
return PoolPara # 返回PoolPara参数
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.MaxPoolProc, self.SetPollPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class FullConn_Class(ModelObj): # 全连接对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.FullConnProc = self.fullconn_proc # 基本操作函数
self.SetFullConnPara = self.setfullconn_para # 参数设置函数
def fullconn_proc(self, inputdata, FullConnPara):
weights = FullConnPara["weights"] # 从FullConnPara参数中获取权重矩阵
bias = FullConnPara["bias"] # 偏置向量
inputdata = inputdata.reshape(1, inputdata.shape[1] * inputdata.shape[2]) # 对输入进行展平处理,变换为单通道的一维数组格式
output = np.dot(inputdata, weights.T) + bias # 计算全连接层的线性变换inputdata与权重矩阵w进行乘法再加上偏置向量b
return output # 返回全连接计算后的数组
# 定义一个函数来设置全连接层的相关参数,这里可以根据实际情况修改或随机生成
def setfullconn_para(self, data, num_outputs):
# 获取池化后的图片数组的长度和宽度
c, height, width = data
num_outputs = num_outputs
weights = np.random.randn(num_outputs, height * width)
bias = np.random.randn(1, num_outputs)
# 返回FullConnPara参数这里用一个字典来存储
FullConnPara = {"weights": weights, "bias": bias, "num_outputs": num_outputs}
return FullConnPara
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.FullConnProc, self.SetFullConnPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class Nonline_Class(ModelObj): # 非线性对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.NonlinearProc = self.nonlinear_proc # 基本操作函数
self.SetNonLPara = self.setnonl_para # 参数设置函数
# 定义非线性函数
def nonlinear_proc(self, inputdata, NonLPara):
nonlinearmode = NonLPara["nonlinearmode"] # 从NonLPara参数中获取非线性函数类型
if nonlinearmode == "Sigmoid": # 判断nonlinearmode进行相应的计算
output = 1 / (1 + np.exp(-inputdata)) # Sigmoid函数将任何实数的输入映射到0和1之间的输出
elif nonlinearmode == "ReLU":
output = np.maximum(inputdata, 0) # ReLU函数将负数输入置为0而正数输入保持不变
elif nonlinearmode == "Tanh":
output = np.tanh(inputdata) # Tanh函数将任何实数的输入映射到-1和1之间的输出
else:
raise ValueError("Invalid nonlinear mode") # 非法的非线性类型,抛出异常
return output # 返回计算后的值
# 定义设置非线性参数的函数
def setnonl_para(self):
# 可以选择"Sigmoid", "ReLU" 或 "Tanh"
nonlinearmode = "ReLU" # 确定参数信息:非线性函数的类型
NonLPara = {"nonlinearmode": nonlinearmode} # 返回NonLPara参数这里用一个字典来存储
return NonLPara # 返回NonLPara参数
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.NonlinearProc, self.SetNonLPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class Label: # 标签
# 设置标签类别列表并将其转化为one-hot向量的形式
def setlabel_para(self, label_list):
num_classes = len(label_list)
identity_matrix = np.eye(num_classes)
label_dict = {label: identity_matrix[i] for i, label in enumerate(label_list)}
return label_dict
# 读取样本数据集,遍历每个样本,并将样本和对应的标签组成元组,返回标记好标签的样本列表
def label_proc(self, samples, labels, label_dict):
labeled_samples = [(sample, label_dict[label]) for sample, label in zip(samples, labels)]
return labeled_samples
def label_array(self, i):
# 读取标签数据
path_csv = 'train.csv'
df = pd.read_csv(path_csv, header=None, skiprows=range(0, i * 32), nrows=(i + 1) * 32 - i * 32)
# print(df)
# 将标签数据转化成数组
right_label = df.iloc[:, 0].tolist()
right_label = list(map(int, right_label))
right_label = [x for x in right_label]
# print(right_label)
return right_label
class Classifier_Class(ModelObj): # 分类对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.ClassifierProc = self.classifier_proc # 基本操作函数
self.SetClassifyPara = self.setclassify_para # 参数设置函数
def classifier_proc(self, inputdata, ClassifyPara):
def softmax(x): # 定义softmax函数
x -= np.max(x) # 减去最大值,防止数值溢出
return np.exp(x) / np.sum(np.exp(x)) # 计算指数和归一化
threshold = ClassifyPara["threshold"] # 从ClassifyPara参数中获取阈值
output = -1 # 初始化输出为-1
prob = softmax(inputdata) # 调用softmax函数得到概率分布向量
prob1 = prob[prob >= threshold] # 如果概率高于阈值,就将该类别加入输出结果
index = np.where(prob == max(prob1)) # 使用where()函数来返回等于概率最大值的元素的索引
output = index[1].item(0) + 1 # 使用item()方法来将索引转换为标准Python标量
return output # 返回分类标签
# 定义设置分类函数参数的函数
def setclassify_para(self):
threshold = 0.1 # 设定阈值,可以根据你的数据和任务来调整阈值
ClassifyPara = {"threshold": threshold} # 返回ClassifyPara参数这里用一个字典来存储
return ClassifyPara # 返回ClassifyPara参数
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.ClassifierProc, self.SetClassifyPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class Error_Class(ModelObj): # 误差计算对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.ErrorProc = self.error_proc # 基本操作函数
self.SetErrorPara = self.seterror_para # 参数设置函数
def error_proc(self, input, label, ErrorPara):
label_list, loss_type = ErrorPara # 读取标签列表和损失函数类型
one_hot_matrix = np.eye(len(label_list)) # 创建一个单位矩阵,大小为标签类别的个数
index = [x for x in label]
# print(label)
label_one_hot = np.take(one_hot_matrix, index, axis=0) # 从one-hot矩阵中取出对应的向量
# print(label_one_hot)
if loss_type == "CEE": # 确定损失函数类别实现不同的损失函数计算输入值与label之间的误差
# 使用交叉熵损失函数,公式为:-sum(label_one_hot * log(input)) / n
loss = -np.sum(label_one_hot * np.log(input)) / len(input)
elif loss_type == "MSE":
# 使用均方误差损失函数公式为sum((input - label_one_hot) ** 2) / n
loss = np.sum((input - label_one_hot) ** 2) / len(input)
elif loss_type == "MAE":
# 使用平均绝对误差损失函数公式为sum(abs(input - label_one_hot)) / n
loss = np.sum(np.abs(input - label_one_hot)) / len(input)
else:
raise ValueError("Invalid loss type") # 如果损失函数类型不在以上三种中,抛出异常
return loss # 返回误差值loss
# 定义设置误差参数的函数
def seterror_para(self):
label_list = [0, 1, 2, 3, 4, 5, 6] # 确定参数信息: 标签类别,损失函数类型
loss_type = "CEE" # 假设损失函数类型为交叉熵Cross Entropy ErrorCEE
ErrorPara = (label_list, loss_type) # 返回ErrorProc参数这里用一个元组来存储
return ErrorPara # 返回ErrorPara参数
def output(self): # 输出方法
# 创建一个空列表
result = [self.ObjID, self.ObjType, self.ObjLable, self.ErrorProc, self.SetErrorPara, self.ParaString, self.ObjX,
self.ObjY]
return result
class AjConv_Class(ModelObj): # 卷积调整对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.AjConvProc = self.ajconv_proc # 基本操作函数
self.SetAjConvPara = self.setajconv_para # 参数设置函数
def ajconv_proc(self, images, AjConvPara):
kernel_grad_list = []
bias_grad = 0 # 初始化偏置项梯度为零
for c in images:
# 计算卷积核和偏置项的梯度
kernel_grad = np.zeros_like(AjConvPara['kernel_info']) # 初始化卷积核梯度为零矩阵
for i in range(AjConvPara['loss'].shape[0]): # 遍历误差值矩阵的行
for j in range(AjConvPara['loss'].shape[1]): # 遍历误差值矩阵的列
# 将输入数据数组中对应的子矩阵旋转180度与误差值相乘累加到卷积核梯度上
kernel_grad += np.rot90(c[i:i + kernel_grad.shape[0], j:j + kernel_grad.shape[0]], 2) * AjConvPara['loss'][i, j]
# 将误差值累加到偏置项梯度上
bias_grad += AjConvPara['loss'][i, j]
kernel_grad_list.append(kernel_grad)
# 使用stack函数沿着第0个轴把一百个a数组堆叠起来
result = np.stack(kernel_grad_list, axis=0)
kernel_grad = np.sum(result, axis=0) / len(images) # 沿着第0个维度求和
# 更新卷积核和偏置项参数
kernel = AjConvPara['kernel_info'] - AjConvPara['learning_rate'] * kernel_grad # 卷积核参数减去学习率乘以卷积核梯度
return kernel # 返回更新后的卷积核
def setajconv_para(self, loss, ConvPara):
kernel = ConvPara['kernel'] # 卷积核信息
learning_rate = 0.01 # 学习率
loss = np.array([[loss]])
AjConvPara = {'kernel_info': kernel, 'learning_rate': learning_rate, 'loss': loss}
return AjConvPara
class AjFullconn_Class(ModelObj): # 全连接调整对象
def __init__(self, ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY):
super().__init__(ObjID, ObjType, ObjLable, ParaString, ObjX, ObjY)
self.AjFullconnProc = self.ajfullconn_proc # 基本操作函数
self.SetAjFCPara = self.setajfc_para # 参数设置函数
def ajfullconn_proc(self, AjFCPara):
# 根据激活函数的参数选择相应的函数和导数
# 计算权重矩阵和偏置向量的梯度,使用链式法则
gradient_weights = np.outer(AjFCPara['loss'], AjFCPara['learning_rate'])
# 更新权重矩阵和偏置向量
weight_matrix = AjFCPara['weights'] - gradient_weights
bias_vector = AjFCPara['bias'] - AjFCPara['learning_rate'] * AjFCPara['bias']
# 返回更新后的权重矩阵和偏置向量
return weight_matrix, bias_vector
def setajfc_para(self, loss, FullConnPara):
weights = FullConnPara["weights"]
bias = FullConnPara["bias"]
loss = np.array([loss])
AjFCPara = {
'weights': weights, # 全连接权重
'bias': bias, # 全连接偏置
'learning_rate': 0.01, # 学习率
'loss': loss # 误差值
}
return AjFCPara
def main():
DataPara = DataSet.SetDataPara() # setload_data()函数,获取加载数据集的参数
train_images, test_images = DataSet.LoadData(DataPara)
ConvPara = Conv.SetConvPara() # 调用SetConvPara()函数,获取卷积层参数
PoolPara = Pool.SetPollPara()
FullConnPara = FullConn.SetFullConnPara((1, 23, 23), 7)
NonLPara = Nonline.SetNonLPara()
ClassifyPara = Classifier.SetClassifyPara()
ErrorPara = Error.SetErrorPara()
LabelPara = Label()
# AjFCPara = AjFullconn.SetAjFCPara()
for i in range(len(train_images) // 32):
images = train_images[i * 32:(i + 1) * 32]
# 存储卷积处理后的图片的列表
conv_images = []
# 获取训练集的图片数据
for image in images:
# 获取矩阵的维度
dim = len(image.shape)
# 如果是二维矩阵,则转化为三维矩阵
if dim == 2:
image_h, image_w = image.shape
image = np.reshape(image, (1, image_h, image_w))
# 调用ConvProc()函数根据ConvPara参数完成卷积计算
output = Conv.ConvProc(image, ConvPara)
# 将卷积结果存储到列表
conv_images.append(output)
# 若为三维矩阵,则保持不变直接卷积处理
elif dim == 3:
output = Conv.ConvProc(image, ConvPara)
conv_images.append(output)
# 将卷积处理后的图片列表转换为数组形式,方便后续处理
conv_images = np.array(conv_images)
pool_images = [] # 存储池化处理后的图片的列表
for image in conv_images: # 获取卷积后的图片数据
output = Pool.MaxPoolProc(image, PoolPara)
pool_images.append(output) # 将池化结果存储到列表
pool_images = np.array(pool_images) # 将池化处理后的图片列表转换为数组形式,方便后续处理
# print(conv_images)
# print(pool_images[0].shape)
# 存储全连接处理后的图片的列表
fullconn_images = []
# 获取池化后的图片数据
for image in pool_images:
output = FullConn.FullConnProc(image, FullConnPara)
# 将全连接处理后的结果存储到列表
fullconn_images.append(output)
# 将全连接处理后的图片列表转换为数组形式,方便后续处理
fullconn_images = np.array(fullconn_images)
# print(fullconn_images)
# 存储非线性处理后的图片的列表
nonlinear_images = []
for image in fullconn_images: # 获取全连接处理后的图片数据
output = Nonline.NonlinearProc(image, NonLPara)
# 将非线性处理后的结果存储到列表
nonlinear_images.append(output)
# 将非线性处理后的图片列表转换为数组形式,方便后续处理
nonlinear_images = np.array(nonlinear_images)
# print(nonlinear_images)
classifier_images = [] # 存储分类处理后的图片的列表
prob_images = [] # 存储分类处理后的概率向量
def softmax(x): # 定义softmax函数
x -= np.max(x) # 减去最大值,防止数值溢出
return np.exp(x) / np.sum(np.exp(x)) # 计算指数和归一化
for image in nonlinear_images: # 获取非线性处理后的图片数据
prob = softmax(image) # 调用softmax函数得到概率分布向量
prob_images.append(prob) # 将概率向量结果存储到列表
output = Classifier.ClassifierProc(image, ClassifyPara) # 进行分类处理
classifier_images.append(output) # 将分类结果存储到列表
classifier_images = np.array(classifier_images) # 将分类的结果列表转换为数组形式,方便后续处理
print(classifier_images)
# print(setlabel_para())
label_dict = LabelPara.setlabel_para([0, 1, 2, 3, 4, 5, 6])
right_label = LabelPara.label_array(i)
labeled_samples = LabelPara.label_proc(images, right_label, label_dict)
print(right_label)
# 假设有以下输入值和真实标签值,输入值是一个概率矩阵,真实标签值是一个类别列表
prob_images = np.squeeze(prob_images)
# print(prob_images)
loss = Error.ErrorProc(prob_images, right_label, ErrorPara) # 计算误差值
print(loss)
AjConvPara = AjConv.SetAjConvPara(loss, ConvPara)
ConvPara['kernel'] = AjConv.AjConvProc(images, AjConvPara)
print(ConvPara['kernel'])
AjFCPara = AjFullconn.SetAjFCPara(loss, FullConnPara)
weight, bias = AjFullconn.AjFullconnProc(AjFCPara)
FullConnPara['weights'] = weight
FullConnPara['bias'] = bias
# print(weight, bias)
if __name__ == '__main__':
DataSet = Data_Class("DataSet1", 1, "数据集1", [], 120, 330)
Conv = Conv_Class("Conv1", 2, "卷积1", [], 250, 330)
Pool = Pool_Class("Pool1", 3, "最大池化1", [], 380, 330)
FullConn = FullConn_Class("FullConn1", 4, "全连接1", [], 510, 330)
Nonline = Nonline_Class("Nonline1", 5, "非线性函数1", [], 640, 330)
Classifier = Classifier_Class("Classifier1", 6, "分类1", [], 780, 330)
Error = Error_Class("Error1", 7, "误差计算1", [], 710, 124)
AjConv = AjConv_Class("AjConv1", 8, "卷积调整1", [], 250, 70)
AjFullconn = AjFullconn_Class("AjFullconn1", 9, "全连接调整1", [], 510, 120)
# AllModelObj = [DataSet, Conv, Pool, FullConn, Nonline, Classifier, Error, AjConv, AjFullconn]
main()

149
X4.py

@ -2,10 +2,9 @@ import sys
import pickle
import subprocess
import tkinter as tk
import ttkbootstrap as ttk
from tkinter import ttk
from tkinter import messagebox
import tkinter.scrolledtext as st
from ttkbootstrap import *
from PIL import Image, ImageTk
from tkinter import Canvas, Frame, BOTH, PhotoImage, filedialog
from X3 import load_data
@ -38,7 +37,7 @@ Fullconn3 = None
global Viewcanvas # 定义画布
global Text # 带滚动条
global Root # 主窗口
global AllModelObj #网络对象
global AllModelObj # 网络对象
List_image = [] # 存储图元的列表
Prob_images = [] # 存储图元的列表
@ -59,20 +58,20 @@ Original_y = 0 # 记录图元原来的y坐标
Offset_x = 0 # 记录鼠标相对于图元的x偏移量
Offset_y = 0 # 记录鼠标相对于图元的y偏移量
Yt = 0 # 新图元的y坐标
Batch = 0 #批次
Batch = 0 # 批次
def create_instance():
# 创建图元对象实例
DataSet = ModelObj("DataSet", 1, "数据集", "LoadData", "SetDataPara", ".", 120, 70).output()
Conv = ModelObj("Conv", 2, "卷积", "ConvProc", "SetConvPara", ".", 280, 70).output()
Pool = ModelObj("Pool", 3, "最大池化", "MaxPoolProc", "SetPollPara", ".", 120, 165).output()
FullConn = ModelObj("FullConn", 4, "全连接", "FullConnProc", "SetFullConnPara", ".", 280, 165).output()
Nonline = ModelObj("Nonline", 5, "非线性函数", "NonlinearProc", "SetNonLPara", ".", 120, 260).output()
Classifier = ModelObj("Classifier", 6, "分类", "ClassifierProc", "SetClassifyPara", ".", 280, 260).output()
Error = ModelObj("Error", 7, "误差计算", "ErrorProc", "SetErrorPara", ".", 120, 355).output()
AjConv = ModelObj("AjConv", 8, "卷积调整", "AjConvProc", "SetAjConvPara", ".", 280, 355).output()
AjFullconn = ModelObj("AjFullconn", 9, "全连接调整", "AjFullconnProc", "SetAjFCPara", ".", 120, 450).output()
AjNonline = ModelObj("AjNonline", 10, "非线性调整", "AjNonlineProc", "SetAjNLPara", ".", 280, 450).output()
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 # 还回图元对象实例列表
@ -81,19 +80,19 @@ def picture_frame(window_width,window_height):
# 计算矩形框的坐标和尺寸
rect1_x = gap # 第一个矩形框的左上角x坐标
rect1_y = gap # 第一个矩形框的左上角y坐标
rect1_width = window_width * 1 / 3 - gap-50 # 第一个矩形框的宽度
rect1_height = window_height * 3 / 4 - gap * 2-50 # 第一个矩形框的高度
rect2_x = window_width * 1 / 3 + gap - 50 # 第二个矩形框的左上角x坐标
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 + 50 # 第二个矩形框的宽度
rect2_height = window_height * 3 / 4 - gap * 2 -50 # 第二个矩形框的高度
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 - 50 # 第三个矩形框的左上角y坐标
rect3_y = window_height * 3 / 4 + gap # 第三个矩形框的左上角y坐标
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
# 创建一个画布,用于绘制矩形框,设置画布的大小和背景色
Viewcanvas = tk.Canvas(Root, width=window_width, height=window_height, bg="blue")
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,
@ -104,7 +103,7 @@ def picture_frame(window_width,window_height):
fill=None, outline="lightblue", width=2)
global Text
Text = st.ScrolledText(Root) # 创建一个带滚动条的文本框,用于展示计算过程
Text.place(x=rect3_x, y=rect3_y, width=1160, height=rect3_height - 1)
Text.place(x=rect3_x, y=rect3_y, width=760, height=rect3_height - 1)
# if __name__ == '__main__':
# Root = tk.Tk()
# # 设置窗口的大小为1200*750
@ -119,7 +118,7 @@ def element(path):
# 加载图元对应的图片文件
img=Image.open(path)
# 使用resize方法调整图片
img = img.resize((70, 60))
img = img.resize((40, 30))
# 把Image对象转换成PhotoImage对象
img = ImageTk.PhotoImage(img)
# 保存图片的引用,防止被垃圾回收
@ -128,47 +127,46 @@ def element(path):
def push_button():
button = {}
# 指定按钮主题为 litera
style = Style(theme='litera')
style = ttk.Style(Root)
# 设置blue.TButton样式的背景色为亮蓝灰前景色为白色
style.configure("blue.TButton", background="LightSlateGray", foreground="white", font=("黑体", 13))
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="white", font=("黑体", 13))
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=500)
button1.place(x=20, y=330)
button['button1'] = button1
button2 = ttk.Button(Root, text=" 训练 ", style="blue.TButton")
button2.place(x=190, y=500)
button2.place(x=140, y=330)
button['button2'] = button2
button3 = ttk.Button(Root, text=" 输出模型程序 ", style="blue.TButton")
button3.place(x=300, y=500)
button3.place(x=240, y=330)
button['button3'] = button3
# 创建五个按钮,用于触发操作
button4 = ttk.Button(Root, text=" 加载已有模型 ", style="green.TButton")
button4.place(x=370, y=5)
button4.place(x=255, y=10)
button['button4'] = button4
button5 = ttk.Button(Root, text=" 新建模型 ", style="green.TButton")
button5.place(x=530, y=5)
button5.place(x=355, y=10)
button['button5'] = button5
button6 = ttk.Button(Root, text=" 图元参数设置 ", style="green.TButton")
button6.place(x=660, y=5)
button6.place(x=435, y=10)
button['button6'] = button6
button7 = ttk.Button(Root, text=" 保存模型 ", style="green.TButton")
button7.place(x=820, y=5)
button7.place(x=535, y=10)
button['button7'] = button7
button8 = ttk.Button(Root, text=" 模型正确性检查 ", style="green.TButton")
button8.place(x=940, y=5)
button8.place(x=615, y=10)
button['button8'] = button8
button9 = ttk.Button(Root, text="退出", style="green.TButton")
button9.place(x=1120, y=5)
button9.place(x=725, y=10)
button['button9'] = button9
return button
@ -330,14 +328,15 @@ def fully_connected(event):
event.widget.coords(Dragged_item, Original_x, Original_y)
# 将新图元的id和坐标添加到列表中
Items1.append((new_item1, x, Yt))
# 创建弹出窗口
top = creat_window("全连接参数配置")
fully_size_entry = create_input_box(top, "全连接输出维度:", 10) # 创建一个输入框,用于输入池大小
top = tk.Toplevel(Root) # 创建弹出窗口
top.geometry("300x250")
top.title("全连接参数配置")
num_outputs_entry = create_input_box(top, "全连接输出维度:", 10)
# 创建
def get_input():
global Listinstance
# 从下拉框中获取输出维度
num = int(fully_size_entry.get())
num = int(num_outputs_entry.get())
# 复制对象的标签
Viewcanvas.create_text(x, Yt + 40, text=str(num) + "--全连接")
if Listinstance[3][5] == ".":
@ -394,12 +393,20 @@ def class_ification(event):
event.widget.coords(Dragged_item, Original_x, Original_y)
# 将新图元的id和坐标添加到列表中
Items1.append((new_item1, x, Yt))
top = creat_window("分类参数配置")
class_size_entry = create_input_box(top, "阈值:", 0.001) # 创建一个输入框,用于分类大小
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(class_size_entry.get())
threshold = float(threshold_entry.get())
# 复制对象的标签
Viewcanvas.create_text(x, Yt + 40, text="输出分类结果")
if Listinstance[5][5] == ".":
@ -623,7 +630,7 @@ def element_binding(obj_x, obj_y, image, y, text):
global Viewcanvas
l1 = Viewcanvas.create_image(obj_x, obj_y, image=image) # 创建图元对象
# 创建图元对象的标签
Viewcanvas.create_text(obj_x - 70, obj_y + y, text=text, font=("黑体", 14))
Viewcanvas.create_text(obj_x - 40, obj_y + y, text=text, font=("黑体", 10))
return l1
def create_left_element(AllModelObj,List_image):
@ -716,7 +723,7 @@ def number_judgments(lsts):
if type(lll) == list:
count.append(lll[1])
sequence.append(index)
if lll[1]==9:
if lll[1]==7:
break
count_2,count_3,count_4=0,0,0
list_count=[]
@ -756,18 +763,18 @@ def load_file():
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=1)
def connecting(obj_x, obj_y, index, x, y1, image, text):
# 创建图元对象
Viewcanvas.create_image(obj_x+(index + x) * 110, obj_y, image=image)
Viewcanvas.create_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():
import copy
@ -778,6 +785,7 @@ def load_model():
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()函数,根据参数加载数据集
# 打印一些信息,检查是否正确加载
@ -785,25 +793,25 @@ def load_model():
print("测试集图片的形状:", Test_images.shape)
# 根据pkl文件的前向传播顺序列表依次识别卷积层、池化层、全连接层、非线性层和分类层的操作
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, 3)
for layer in range(len(count)):
if count[layer] == 2: # 如果是卷积层将读取的卷积层的信息存储到Conv实例
if counts[layer]%10 == 1:
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:
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:
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:
if counts[layer] % 10 == 1:
global Pool1
Listinstance[2] =copy.deepcopy(lsts[sequence[layer]])
Pool1 = lsts[sequence[layer]]
@ -842,25 +850,9 @@ def load_model():
if count[layer] == 7: # 如果是计算误差层将读取的信息存储到Error实例
Listinstance[6] = lsts[sequence[layer]]
connecting(x-30, y-120, layer, 0, 45, List_image[6], '计算误差')
Viewcanvas.create_line(x + layer * 110 + 25, y, x + layer * 110 + 10, y - 60,
x + 5 * 110 - 20, y - 120, arrow=tk.LAST, arrowshape=(16, 20, 4),
fill='lightblue', smooth=True, width=2)
# 创建图元对象
Viewcanvas.create_image(600, 180, image=List_image[7])
# 创建图元对象的标签
Viewcanvas.create_text(600, 230, text='调整1', font=("黑体", 14))
Viewcanvas.create_line(x + layer * 110 - 50, y - 140, 630, 165, arrow=tk.LAST, arrowshape=(16, 20, 4),
fill='lightblue', smooth=True, width=2)
Viewcanvas.create_line(600, 200, x + 1 * 110, y - 20, arrow=tk.LAST, arrowshape=(16, 20, 4),
fill='lightblue', smooth=True, width=2)
# 创建图元对象
Viewcanvas.create_image(860, 200, image=List_image[7])
# 创建图元对象的标签
Viewcanvas.create_text(860, 250, text='调整2', font=("黑体", 14))
Viewcanvas.create_line(x + layer * 110 - 60, y - 120, 875, 200, arrow=tk.LAST, arrowshape=(16, 20, 4),
fill='lightblue', smooth=True, width=2)
Viewcanvas.create_line(835, 200, x + (layer - 2) * 110 + 10, y - 20, arrow=tk.LAST, arrowshape=(16, 20, 4),
fill='lightblue', smooth=True, width=2)
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
@ -1108,6 +1100,7 @@ def create_window(number,count,list1,list2,list3,list4,list5,list6):
para = float(para)
window = creat_window('分类参数调整') # 创建一个新的窗口
threshold_entry = create_input_box(window, "阈值:", para) # 创建一个输入框,用于输入阈值
def modify_para():
# 获取输入框的内容
threshold = threshold_entry.get()
@ -1191,10 +1184,10 @@ if __name__ == '__main__':
# 创建一个主窗口
Root = tk.Tk()
# 设置窗口的大小为1200*750
window_width = 1200 # 窗口的宽度
window_height = 750 # 窗口的高度
window_width = 800 # 窗口的宽度
window_height = 450 # 窗口的高度
Root.title("神经网络可视化")
Root.geometry("1200x750") # 设置窗口的大小和位置
Root.geometry("800x450") # 设置窗口的大小和位置
picture_frame(window_width,window_height)
Listinstance = create_instance()
listclass = connect_class(Listinstance)

File diff suppressed because it is too large Load Diff

434
X5.py

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

2621
X5_1.py

File diff suppressed because it is too large Load Diff

2410
X5_2.py

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

@ -0,0 +1,54 @@
import os
import csv
import shutil
import pandas as pd
def index_label(photo_folder, csv_name):
# 读取照片数据文件夹
photo_files = os.listdir(photo_folder)
# 提取数字作为索引
indexes = [int(os.path.splitext(file)[0]) for file in photo_files]
# 打开原始CSV文件和新的CSV文件
csv_file = 'data/emotion.csv'
new_csv_file = 'data/'+csv_name+'.csv'
with open(csv_file, 'r') as file:
reader = csv.reader(file)
data = list(reader)
# 添加索引列
header = ['索引', '标签']
result = [header] + [[index, data[index][0]] + data[index][1:] for index in indexes if index < len(data)]
# 将结果保存为新的CSV文件
# new_csv_file = '新的CSV文件路径'
with open(new_csv_file, 'w', newline='') as file:
writer = csv.writer(file)
writer.writerows(result)
def image_classification(photo_folder, csv_name):
# 读取包含索引和标签的数据文件
# 定义要删除的文件夹路径
target_folder = 'data_classification/' + csv_name # 目标文件夹路径
# 遍历文件夹中的文件并删除
for filename in os.listdir(target_folder):
file_path = os.path.join(target_folder, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path) # 删除文件
elif os.path.isdir(file_path):
shutil.rmtree(file_path) # 递归删除文件夹及其内容
except Exception as e:
print(f'无法删除文件:{file_path}')
new_csv_file = 'data/' + csv_name + '.csv'
df = pd.read_csv(new_csv_file, encoding='GBK')
# 设置原始文件夹路径和目标文件夹路径
# 遍历 DataFrame
for index, row in df.iterrows():
file_index = row['索引'] # 索引对应的列名
file_label = row['标签'] # 标签对应的列名
source_file = os.path.join(photo_folder, f'{file_index}.jpg') # 原始文件路径
target_folder_label = os.path.join(target_folder, str(file_label)) # 目标文件夹路径
# 创建对应标签的目标文件夹(如果不存在)
os.makedirs(target_folder_label, exist_ok=True)
# 复制文件到目标文件夹
shutil.copy(source_file, target_folder_label)

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

@ -0,0 +1,901 @@
索引,标签
0,0
1,0
10,0
100,3
101,2
102,6
103,3
104,4
105,3
106,2
107,0
108,2
109,3
11,6
110,2
111,3
112,6
113,6
114,3
115,4
116,4
117,0
118,3
119,3
12,6
120,0
121,2
122,0
123,0
124,3
125,3
126,0
127,4
128,5
129,2
13,6
130,4
131,2
132,5
133,3
134,0
135,6
136,6
137,2
138,2
139,3
14,3
140,2
141,3
142,3
143,3
144,3
145,3
146,4
147,2
148,2
149,0
15,5
150,0
151,2
152,6
153,3
154,4
155,5
156,3
157,0
158,2
159,4
16,3
160,5
161,2
162,3
163,4
164,6
165,3
166,4
167,3
168,6
169,0
17,2
170,4
171,4
172,4
173,2
174,6
175,5
176,5
177,6
178,5
179,2
18,6
180,3
181,2
182,3
183,4
184,0
185,2
186,0
187,3
188,0
189,2
19,4
190,2
191,5
192,3
193,5
194,5
195,4
196,3
197,0
198,6
199,5
2,2
20,4
200,2
201,6
202,0
203,0
204,4
205,5
206,6
207,3
208,5
209,5
21,2
210,3
211,2
212,2
213,3
214,3
215,3
216,3
217,6
218,3
219,6
22,0
220,3
221,0
222,6
223,3
224,2
225,0
226,6
227,5
228,6
229,0
23,0
230,5
231,4
232,3
233,0
234,3
235,0
236,4
237,5
238,4
239,3
24,3
240,3
241,0
242,0
243,6
244,2
245,0
246,6
247,3
248,0
249,0
25,3
250,6
251,0
252,5
253,6
254,3
255,2
256,5
257,5
258,2
259,0
26,5
260,2
261,6
262,6
263,0
264,2
265,3
266,4
267,2
268,6
269,5
27,0
270,2
271,2
272,6
273,6
274,6
275,2
276,5
277,3
278,0
279,5
28,3
280,0
281,4
282,3
283,3
284,3
285,3
286,6
287,3
288,2
289,4
29,5
290,6
291,3
292,2
293,4
294,0
295,0
296,3
297,2
298,0
299,1
3,4
30,3
300,2
301,2
302,5
303,3
304,5
305,4
306,4
307,0
308,2
309,3
31,6
310,4
311,6
312,4
313,2
314,2
315,3
316,5
317,4
318,4
319,5
32,3
320,6
321,4
322,5
323,0
324,3
325,3
326,3
327,2
328,5
329,5
33,2
330,5
331,3
332,5
333,3
334,3
335,3
336,5
337,6
338,0
339,4
34,3
340,2
341,2
342,0
343,4
344,5
345,5
346,6
347,6
348,3
349,2
35,6
350,4
351,2
352,4
353,0
354,5
355,0
356,3
357,5
358,2
359,4
36,6
360,0
361,4
362,5
363,6
364,3
365,2
366,3
367,5
368,0
369,0
37,6
370,3
371,3
372,2
373,6
374,0
375,2
376,6
377,0
378,3
379,2
38,0
380,3
381,2
382,6
383,4
384,3
385,4
386,4
387,0
388,1
389,2
39,5
390,4
391,6
392,5
393,0
394,4
395,6
396,6
397,6
398,2
399,6
4,6
40,0
400,4
401,3
402,2
403,4
404,0
405,6
406,3
407,2
408,3
409,0
41,3
410,6
411,5
412,0
413,5
414,2
415,6
416,1
417,3
418,2
419,6
42,4
420,2
421,0
422,4
423,6
424,4
425,5
426,4
427,4
428,2
429,0
43,0
430,4
431,0
432,2
433,0
434,0
435,5
436,3
437,3
438,5
439,3
44,6
440,3
441,4
442,6
443,5
444,3
445,3
446,3
447,4
448,4
449,6
45,2
450,3
451,4
452,2
453,3
454,2
455,2
456,3
457,4
458,3
459,6
46,3
460,2
461,6
462,4
463,3
464,0
465,3
466,4
467,6
468,6
469,0
47,6
470,0
471,5
472,3
473,1
474,2
475,4
476,2
477,2
478,3
479,2
48,2
480,5
481,0
482,6
483,2
484,4
485,3
486,2
487,3
488,5
489,0
49,2
490,6
491,6
492,5
493,6
494,5
495,3
496,0
497,5
498,6
499,0
5,2
50,2
500,2
501,6
502,6
503,6
504,2
505,4
506,6
507,2
508,6
509,0
51,5
510,5
511,3
512,3
513,4
514,4
515,0
516,0
517,2
518,5
519,0
52,5
520,6
521,0
522,6
523,5
524,4
525,0
526,0
527,3
528,5
529,5
53,6
530,4
531,3
532,3
533,1
534,4
535,6
536,6
537,3
538,2
539,3
54,4
540,3
541,6
542,6
543,4
544,6
545,0
546,2
547,6
548,5
549,4
55,5
550,2
551,6
552,6
553,3
554,5
555,6
556,4
557,6
558,0
559,4
56,0
560,2
561,3
562,3
563,0
564,0
565,6
566,2
567,6
568,3
569,3
57,3
570,6
571,5
572,3
573,1
574,3
575,2
576,2
577,4
578,2
579,2
58,4
580,4
581,0
582,3
583,5
584,6
585,3
586,3
587,2
588,3
589,0
59,2
590,4
591,2
592,6
593,2
594,3
595,5
596,6
597,2
598,4
599,2
6,4
60,6
600,2
601,6
602,6
603,4
604,6
605,6
606,3
607,4
608,0
609,3
61,5
610,4
611,4
612,0
613,3
614,4
615,6
616,4
617,0
618,4
619,6
62,3
620,3
621,5
622,2
623,3
624,0
625,0
626,3
627,6
628,3
629,3
63,4
630,6
631,4
632,5
633,0
634,2
635,3
636,0
637,3
638,5
639,3
64,3
640,4
641,3
642,4
643,6
644,6
645,3
646,4
647,5
648,3
649,6
65,0
650,4
651,6
652,5
653,3
654,0
655,3
656,2
657,3
658,3
659,3
66,4
660,5
661,5
662,6
663,2
664,3
665,0
666,3
667,3
668,3
669,2
67,3
670,5
671,0
672,6
673,6
674,3
675,5
676,0
677,0
678,3
679,6
68,0
680,4
681,3
682,3
683,5
684,3
685,3
686,5
687,3
688,4
689,2
69,5
690,3
691,3
692,5
693,3
694,6
695,5
696,4
697,4
698,5
699,6
7,3
70,4
700,0
701,2
702,2
703,4
704,0
705,6
706,3
707,2
708,5
709,2
71,2
710,2
711,4
712,2
713,3
714,0
715,6
716,0
717,6
718,2
719,5
72,4
720,3
721,3
722,3
723,2
724,3
725,6
726,5
727,0
728,3
729,2
73,2
730,4
731,2
732,6
733,4
734,3
735,4
736,3
737,3
738,3
739,2
74,0
740,0
741,2
742,5
743,0
744,2
745,2
746,2
747,6
748,2
749,4
75,6
750,5
751,5
752,4
753,4
754,4
755,2
756,0
757,6
758,1
759,5
76,0
760,3
761,4
762,6
763,5
764,0
765,0
766,6
767,6
768,2
769,2
77,0
770,4
771,5
772,6
773,2
774,3
775,3
776,4
777,5
778,0
779,4
78,5
780,3
781,6
782,4
783,5
784,5
785,6
786,3
787,6
788,5
789,5
79,4
790,0
791,3
792,3
793,6
794,2
795,6
796,5
797,0
798,4
799,2
8,3
80,3
800,4
801,6
802,3
803,3
804,2
805,4
806,2
807,1
808,4
809,3
81,5
810,3
811,2
812,4
813,3
814,5
815,2
816,0
817,3
818,4
819,5
82,3
820,3
821,3
822,4
823,0
824,0
825,2
826,1
827,3
828,4
829,3
83,6
830,3
831,4
832,6
833,2
834,0
835,0
836,2
837,5
838,6
839,4
84,2
840,3
841,6
842,0
843,5
844,4
845,1
846,2
847,2
848,5
849,3
85,2
850,0
851,0
852,6
853,5
854,0
855,6
856,3
857,5
858,6
859,2
86,4
860,0
861,0
862,2
863,3
864,1
865,5
866,4
867,5
868,5
869,2
87,4
870,3
871,2
872,2
873,3
874,6
875,6
876,0
877,6
878,4
879,0
88,5
880,3
881,0
882,4
883,0
884,6
885,6
886,2
887,3
888,5
889,4
89,4
890,2
891,6
892,3
893,5
894,5
895,3
896,2
897,3
898,3
899,4
9,2
90,0
91,0
92,6
93,0
94,6
95,2
96,2
97,3
98,4
99,3
1 索引 标签
2 0 0
3 1 0
4 10 0
5 100 3
6 101 2
7 102 6
8 103 3
9 104 4
10 105 3
11 106 2
12 107 0
13 108 2
14 109 3
15 11 6
16 110 2
17 111 3
18 112 6
19 113 6
20 114 3
21 115 4
22 116 4
23 117 0
24 118 3
25 119 3
26 12 6
27 120 0
28 121 2
29 122 0
30 123 0
31 124 3
32 125 3
33 126 0
34 127 4
35 128 5
36 129 2
37 13 6
38 130 4
39 131 2
40 132 5
41 133 3
42 134 0
43 135 6
44 136 6
45 137 2
46 138 2
47 139 3
48 14 3
49 140 2
50 141 3
51 142 3
52 143 3
53 144 3
54 145 3
55 146 4
56 147 2
57 148 2
58 149 0
59 15 5
60 150 0
61 151 2
62 152 6
63 153 3
64 154 4
65 155 5
66 156 3
67 157 0
68 158 2
69 159 4
70 16 3
71 160 5
72 161 2
73 162 3
74 163 4
75 164 6
76 165 3
77 166 4
78 167 3
79 168 6
80 169 0
81 17 2
82 170 4
83 171 4
84 172 4
85 173 2
86 174 6
87 175 5
88 176 5
89 177 6
90 178 5
91 179 2
92 18 6
93 180 3
94 181 2
95 182 3
96 183 4
97 184 0
98 185 2
99 186 0
100 187 3
101 188 0
102 189 2
103 19 4
104 190 2
105 191 5
106 192 3
107 193 5
108 194 5
109 195 4
110 196 3
111 197 0
112 198 6
113 199 5
114 2 2
115 20 4
116 200 2
117 201 6
118 202 0
119 203 0
120 204 4
121 205 5
122 206 6
123 207 3
124 208 5
125 209 5
126 21 2
127 210 3
128 211 2
129 212 2
130 213 3
131 214 3
132 215 3
133 216 3
134 217 6
135 218 3
136 219 6
137 22 0
138 220 3
139 221 0
140 222 6
141 223 3
142 224 2
143 225 0
144 226 6
145 227 5
146 228 6
147 229 0
148 23 0
149 230 5
150 231 4
151 232 3
152 233 0
153 234 3
154 235 0
155 236 4
156 237 5
157 238 4
158 239 3
159 24 3
160 240 3
161 241 0
162 242 0
163 243 6
164 244 2
165 245 0
166 246 6
167 247 3
168 248 0
169 249 0
170 25 3
171 250 6
172 251 0
173 252 5
174 253 6
175 254 3
176 255 2
177 256 5
178 257 5
179 258 2
180 259 0
181 26 5
182 260 2
183 261 6
184 262 6
185 263 0
186 264 2
187 265 3
188 266 4
189 267 2
190 268 6
191 269 5
192 27 0
193 270 2
194 271 2
195 272 6
196 273 6
197 274 6
198 275 2
199 276 5
200 277 3
201 278 0
202 279 5
203 28 3
204 280 0
205 281 4
206 282 3
207 283 3
208 284 3
209 285 3
210 286 6
211 287 3
212 288 2
213 289 4
214 29 5
215 290 6
216 291 3
217 292 2
218 293 4
219 294 0
220 295 0
221 296 3
222 297 2
223 298 0
224 299 1
225 3 4
226 30 3
227 300 2
228 301 2
229 302 5
230 303 3
231 304 5
232 305 4
233 306 4
234 307 0
235 308 2
236 309 3
237 31 6
238 310 4
239 311 6
240 312 4
241 313 2
242 314 2
243 315 3
244 316 5
245 317 4
246 318 4
247 319 5
248 32 3
249 320 6
250 321 4
251 322 5
252 323 0
253 324 3
254 325 3
255 326 3
256 327 2
257 328 5
258 329 5
259 33 2
260 330 5
261 331 3
262 332 5
263 333 3
264 334 3
265 335 3
266 336 5
267 337 6
268 338 0
269 339 4
270 34 3
271 340 2
272 341 2
273 342 0
274 343 4
275 344 5
276 345 5
277 346 6
278 347 6
279 348 3
280 349 2
281 35 6
282 350 4
283 351 2
284 352 4
285 353 0
286 354 5
287 355 0
288 356 3
289 357 5
290 358 2
291 359 4
292 36 6
293 360 0
294 361 4
295 362 5
296 363 6
297 364 3
298 365 2
299 366 3
300 367 5
301 368 0
302 369 0
303 37 6
304 370 3
305 371 3
306 372 2
307 373 6
308 374 0
309 375 2
310 376 6
311 377 0
312 378 3
313 379 2
314 38 0
315 380 3
316 381 2
317 382 6
318 383 4
319 384 3
320 385 4
321 386 4
322 387 0
323 388 1
324 389 2
325 39 5
326 390 4
327 391 6
328 392 5
329 393 0
330 394 4
331 395 6
332 396 6
333 397 6
334 398 2
335 399 6
336 4 6
337 40 0
338 400 4
339 401 3
340 402 2
341 403 4
342 404 0
343 405 6
344 406 3
345 407 2
346 408 3
347 409 0
348 41 3
349 410 6
350 411 5
351 412 0
352 413 5
353 414 2
354 415 6
355 416 1
356 417 3
357 418 2
358 419 6
359 42 4
360 420 2
361 421 0
362 422 4
363 423 6
364 424 4
365 425 5
366 426 4
367 427 4
368 428 2
369 429 0
370 43 0
371 430 4
372 431 0
373 432 2
374 433 0
375 434 0
376 435 5
377 436 3
378 437 3
379 438 5
380 439 3
381 44 6
382 440 3
383 441 4
384 442 6
385 443 5
386 444 3
387 445 3
388 446 3
389 447 4
390 448 4
391 449 6
392 45 2
393 450 3
394 451 4
395 452 2
396 453 3
397 454 2
398 455 2
399 456 3
400 457 4
401 458 3
402 459 6
403 46 3
404 460 2
405 461 6
406 462 4
407 463 3
408 464 0
409 465 3
410 466 4
411 467 6
412 468 6
413 469 0
414 47 6
415 470 0
416 471 5
417 472 3
418 473 1
419 474 2
420 475 4
421 476 2
422 477 2
423 478 3
424 479 2
425 48 2
426 480 5
427 481 0
428 482 6
429 483 2
430 484 4
431 485 3
432 486 2
433 487 3
434 488 5
435 489 0
436 49 2
437 490 6
438 491 6
439 492 5
440 493 6
441 494 5
442 495 3
443 496 0
444 497 5
445 498 6
446 499 0
447 5 2
448 50 2
449 500 2
450 501 6
451 502 6
452 503 6
453 504 2
454 505 4
455 506 6
456 507 2
457 508 6
458 509 0
459 51 5
460 510 5
461 511 3
462 512 3
463 513 4
464 514 4
465 515 0
466 516 0
467 517 2
468 518 5
469 519 0
470 52 5
471 520 6
472 521 0
473 522 6
474 523 5
475 524 4
476 525 0
477 526 0
478 527 3
479 528 5
480 529 5
481 53 6
482 530 4
483 531 3
484 532 3
485 533 1
486 534 4
487 535 6
488 536 6
489 537 3
490 538 2
491 539 3
492 54 4
493 540 3
494 541 6
495 542 6
496 543 4
497 544 6
498 545 0
499 546 2
500 547 6
501 548 5
502 549 4
503 55 5
504 550 2
505 551 6
506 552 6
507 553 3
508 554 5
509 555 6
510 556 4
511 557 6
512 558 0
513 559 4
514 56 0
515 560 2
516 561 3
517 562 3
518 563 0
519 564 0
520 565 6
521 566 2
522 567 6
523 568 3
524 569 3
525 57 3
526 570 6
527 571 5
528 572 3
529 573 1
530 574 3
531 575 2
532 576 2
533 577 4
534 578 2
535 579 2
536 58 4
537 580 4
538 581 0
539 582 3
540 583 5
541 584 6
542 585 3
543 586 3
544 587 2
545 588 3
546 589 0
547 59 2
548 590 4
549 591 2
550 592 6
551 593 2
552 594 3
553 595 5
554 596 6
555 597 2
556 598 4
557 599 2
558 6 4
559 60 6
560 600 2
561 601 6
562 602 6
563 603 4
564 604 6
565 605 6
566 606 3
567 607 4
568 608 0
569 609 3
570 61 5
571 610 4
572 611 4
573 612 0
574 613 3
575 614 4
576 615 6
577 616 4
578 617 0
579 618 4
580 619 6
581 62 3
582 620 3
583 621 5
584 622 2
585 623 3
586 624 0
587 625 0
588 626 3
589 627 6
590 628 3
591 629 3
592 63 4
593 630 6
594 631 4
595 632 5
596 633 0
597 634 2
598 635 3
599 636 0
600 637 3
601 638 5
602 639 3
603 64 3
604 640 4
605 641 3
606 642 4
607 643 6
608 644 6
609 645 3
610 646 4
611 647 5
612 648 3
613 649 6
614 65 0
615 650 4
616 651 6
617 652 5
618 653 3
619 654 0
620 655 3
621 656 2
622 657 3
623 658 3
624 659 3
625 66 4
626 660 5
627 661 5
628 662 6
629 663 2
630 664 3
631 665 0
632 666 3
633 667 3
634 668 3
635 669 2
636 67 3
637 670 5
638 671 0
639 672 6
640 673 6
641 674 3
642 675 5
643 676 0
644 677 0
645 678 3
646 679 6
647 68 0
648 680 4
649 681 3
650 682 3
651 683 5
652 684 3
653 685 3
654 686 5
655 687 3
656 688 4
657 689 2
658 69 5
659 690 3
660 691 3
661 692 5
662 693 3
663 694 6
664 695 5
665 696 4
666 697 4
667 698 5
668 699 6
669 7 3
670 70 4
671 700 0
672 701 2
673 702 2
674 703 4
675 704 0
676 705 6
677 706 3
678 707 2
679 708 5
680 709 2
681 71 2
682 710 2
683 711 4
684 712 2
685 713 3
686 714 0
687 715 6
688 716 0
689 717 6
690 718 2
691 719 5
692 72 4
693 720 3
694 721 3
695 722 3
696 723 2
697 724 3
698 725 6
699 726 5
700 727 0
701 728 3
702 729 2
703 73 2
704 730 4
705 731 2
706 732 6
707 733 4
708 734 3
709 735 4
710 736 3
711 737 3
712 738 3
713 739 2
714 74 0
715 740 0
716 741 2
717 742 5
718 743 0
719 744 2
720 745 2
721 746 2
722 747 6
723 748 2
724 749 4
725 75 6
726 750 5
727 751 5
728 752 4
729 753 4
730 754 4
731 755 2
732 756 0
733 757 6
734 758 1
735 759 5
736 76 0
737 760 3
738 761 4
739 762 6
740 763 5
741 764 0
742 765 0
743 766 6
744 767 6
745 768 2
746 769 2
747 77 0
748 770 4
749 771 5
750 772 6
751 773 2
752 774 3
753 775 3
754 776 4
755 777 5
756 778 0
757 779 4
758 78 5
759 780 3
760 781 6
761 782 4
762 783 5
763 784 5
764 785 6
765 786 3
766 787 6
767 788 5
768 789 5
769 79 4
770 790 0
771 791 3
772 792 3
773 793 6
774 794 2
775 795 6
776 796 5
777 797 0
778 798 4
779 799 2
780 8 3
781 80 3
782 800 4
783 801 6
784 802 3
785 803 3
786 804 2
787 805 4
788 806 2
789 807 1
790 808 4
791 809 3
792 81 5
793 810 3
794 811 2
795 812 4
796 813 3
797 814 5
798 815 2
799 816 0
800 817 3
801 818 4
802 819 5
803 82 3
804 820 3
805 821 3
806 822 4
807 823 0
808 824 0
809 825 2
810 826 1
811 827 3
812 828 4
813 829 3
814 83 6
815 830 3
816 831 4
817 832 6
818 833 2
819 834 0
820 835 0
821 836 2
822 837 5
823 838 6
824 839 4
825 84 2
826 840 3
827 841 6
828 842 0
829 843 5
830 844 4
831 845 1
832 846 2
833 847 2
834 848 5
835 849 3
836 85 2
837 850 0
838 851 0
839 852 6
840 853 5
841 854 0
842 855 6
843 856 3
844 857 5
845 858 6
846 859 2
847 86 4
848 860 0
849 861 0
850 862 2
851 863 3
852 864 1
853 865 5
854 866 4
855 867 5
856 868 5
857 869 2
858 87 4
859 870 3
860 871 2
861 872 2
862 873 3
863 874 6
864 875 6
865 876 0
866 877 6
867 878 4
868 879 0
869 88 5
870 880 3
871 881 0
872 882 4
873 883 0
874 884 6
875 885 6
876 886 2
877 887 3
878 888 5
879 889 4
880 89 4
881 890 2
882 891 6
883 892 3
884 893 5
885 894 5
886 895 3
887 896 2
888 897 3
889 898 3
890 899 4
891 9 2
892 90 0
893 91 0
894 92 6
895 93 0
896 94 6
897 95 2
898 96 2
899 97 3
900 98 4
901 99 3

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save