csv文件转record文件generate_tfrecord.py

本文介绍了如何使用Python脚本将CSV标注文件转换为TensorFlow Record(TFRecord)格式,适用于带有多个类别标签的图像数据,如猫、狗等。通过flags参数灵活指定类别,并生成对应的训练集和测试集文件。
部署运行你感兴趣的模型镜像

 

"""
Usage:

# Create train data:
python generate_tfrecord.py --label=<LABEL> --csv_input=<PATH_TO_ANNOTATIONS_FOLDER>/train_labels.csv  --output_path=<PATH_TO_ANNOTATIONS_FOLDER>/train.record

# Create test data:
python generate_tfrecord.py --label=<LABEL> --csv_input=<PATH_TO_ANNOTATIONS_FOLDER>/test_labels.csv  --output_path=<PATH_TO_ANNOTATIONS_FOLDER>/test.record
"""

from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

import os
import io
import pandas as pd
import tensorflow as tf
import sys
sys.path.append("../../models/research")

from PIL import Image
from object_detection.utils import dataset_util
from collections import namedtuple, OrderedDict

flags = tf.app.flags
flags.DEFINE_string('csv_input', '', 'Path to the CSV input')
flags.DEFINE_string('output_path', '', 'Path to output TFRecord')
# flags.DEFINE_string('label', '', 'Name of class label')
# if your image has more labels input them as
flags.DEFINE_string('label0', '', 'Name of class[0] label')
flags.DEFINE_string('label1', '', 'Name of class[1] label')
# flags.DEFINE_string('label2', '', 'Name of class[2] label')
# flags.DEFINE_string('label3', '', 'Name of class[3] label')
# flags.DEFINE_string('label4', '', 'Name of class[4] label')
# flags.DEFINE_string('label5', '', 'Name of class[5] label')
# flags.DEFINE_string('label6', '', 'Name of class[6] label')
# and so on.
flags.DEFINE_string('img_path', '', 'Path to images')
FLAGS = flags.FLAGS


# TO-DO replace this with label map
# for multiple labels add more else if statements
def class_text_to_int(row_label):
    # if row_label == FLAGS.label:
    #    return 1
    
    if row_label == 'cat':
        return 1
    elif row_label == 'dog':
        return 2
    # elif row_label == FLAGS.label2:
    #    return 3
    # elif row_label == FLAGS.label3:
    #    return 4
    # elif row_label == FLAGS.label4:
    #    return 5
    # elif row_label == FLAGS.label5:
    #    return 6
    # elif row_label == FLAGS.label6:
    #    return 7
    else:
        None


def split(df, group):
    data = namedtuple('data', ['filename', 'object'])
    gb = df.groupby(group)
    return [data(filename, gb.get_group(x)) for filename, x in zip(gb.groups.keys(), gb.groups)]


def create_tf_example(group, path):
    with tf.gfile.GFile(os.path.join(path, '{}'.format(group.filename)), 'rb') as fid:
        encoded_jpg = fid.read()
    encoded_jpg_io = io.BytesIO(encoded_jpg)
    image = Image.open(encoded_jpg_io)
    width, height = image.size

    filename = group.filename.encode('utf8')
    image_format = b'jpg'
    # check if the image format is matching with your images.
    xmins = []
    xmaxs = []
    ymins = []
    ymaxs = []
    classes_text = []
    classes = []

    for index, row in group.object.iterrows():
        xmins.append(row['xmin'] / width)
        xmaxs.append(row['xmax'] / width)
        ymins.append(row['ymin'] / height)
        ymaxs.append(row['ymax'] / height)
        classes_text.append(row['class'].encode('utf8'))
        classes.append(class_text_to_int(row['class']))

    tf_example = tf.train.Example(features=tf.train.Features(feature={
        'image/height': dataset_util.int64_feature(height),
        'image/width': dataset_util.int64_feature(width),
        'image/filename': dataset_util.bytes_feature(filename),
        'image/source_id': dataset_util.bytes_feature(filename),
        'image/encoded': dataset_util.bytes_feature(encoded_jpg),
        'image/format': dataset_util.bytes_feature(image_format),
        'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),
        'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),
        'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),
        'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),
        'image/object/class/text': dataset_util.bytes_list_feature(classes_text),
        'image/object/class/label': dataset_util.int64_list_feature(classes),
    }))
    return tf_example


def main(_):
    writer = tf.python_io.TFRecordWriter(FLAGS.output_path)
    path = os.path.join(os.getcwd(), FLAGS.img_path)
    examples = pd.read_csv(FLAGS.csv_input)
    grouped = split(examples, 'filename')
    for group in grouped:
        tf_example = create_tf_example(group, path)
        writer.write(tf_example.SerializeToString())

    writer.close()
    output_path = os.path.join(os.getcwd(), FLAGS.output_path)
    print('Successfully created the TFRecords: {}'.format(output_path))


if __name__ == '__main__':
    tf.app.run()

 类别写成相应的类别,就不会有错误了

您可能感兴趣的与本文相关的镜像

TensorFlow-v2.15

TensorFlow-v2.15

TensorFlow

TensorFlow 是由Google Brain 团队开发的开源机器学习框架,广泛应用于深度学习研究和生产环境。 它提供了一个灵活的平台,用于构建和训练各种机器学习模型

import tkinter as tk from tkinter import ttk import time import sys import os import platform import ctypes import csv import threading import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from ctypes import windll, wintypes from collections import defaultdict from datetime import datetime # 解决中文警告问题 import matplotlib as mpl mpl.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] # 指定默认字体 mpl.rcParams['axes.unicode_minus'] = False # 解决负号显示问题 class HighPrecisionTimer: """高精度计时器基类""" def __init__(self): self.start_time = 0 self.total_elapsed = 0 self.running = False self.interrupt_count = 0 # 中断计数器 self.records = [] # 记录每次计时结果 def start(self): """开始计时""" if not self.running: self.start_time = self.current_time() self.running = True def stop(self): """停止计时""" if self.running: elapsed = self.current_time() - self.start_time self.total_elapsed += elapsed self.running = False def reset(self): """重置计时器""" self.total_elapsed = 0 self.running = False self.interrupt_count = 0 self.records = [] def current_elapsed(self): """获取当前已过时间(毫秒)""" if self.running: return self.total_elapsed + (self.current_time() - self.start_time) return self.total_elapsed def current_time(self): """抽象方法,由子类实现具体计时方案""" raise NotImplementedError("Subclasses must implement current_time()") def record_current(self): """记录当前计时值""" if self.running: elapsed = self.current_elapsed() self.records.append({ "timestamp": datetime.now(), "elapsed": elapsed, "label": f"记录 {len(self.records)+1}" }) return elapsed return 0 def get_cpu_utilization(self, physical_time): if physical_time > 0: return min(100, max(0, (self.current_elapsed() / physical_time) * 100)) return 0 def record_interrupt(self): """记录中断事件""" self.interrupt_count += 1 class PerformanceCounterTimer(HighPrecisionTimer): """基于性能计数器的物理计时方案""" def __init__(self): super().__init__() # 获取性能计数器频率 if platform.system() == 'Windows': self.frequency = ctypes.c_int64() windll.kernel32.QueryPerformanceFrequency(ctypes.byref(self.frequency)) self.frequency = self.frequency.value else: # Linux/macOS使用time.perf_counter self.frequency = 1e9 # 1秒 = 1e9纳秒 def current_time(self): """获取当前性能计数器时间(毫秒)""" if platform.system() == 'Windows': counter = ctypes.c_int64() windll.kernel32.QueryPerformanceCounter(ctypes.byref(counter)) return (counter.value * 1000) / self.frequency # 换为毫秒 else: # 跨平台方案 return time.perf_counter() * 1000 class CPUCycleTimer(HighPrecisionTimer): """基于CPU周期的计时方案""" def __init__(self): super().__init__() # 获取CPU频率 self.frequency = self.get_cpu_frequency() self.power_model = self.create_power_model() # 创建功耗模型 def get_cpu_frequency(self): """尝试获取CPU频率""" try: if platform.system() == 'Windows': # Windows获取CPU频率 import winreg key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\CentralProcessor\0") value, _ = winreg.QueryValueEx(key, "~MHz") winreg.CloseKey(key) return value * 1e6 # MHz换为Hz else: # Linux/macOS获取CPU频率 with open('/proc/cpuinfo') as f: for line in f: if 'cpu MHz' in line: return float(line.split(':')[1].strip()) * 1e6 # 默认值 return 3.5e9 # 3.5 GHz except: return 3.5e9 # 3.5 GHz def current_time(self): """获取当前CPU周期计数并换为毫秒""" if platform.system() == 'Windows': return time.perf_counter_ns() / 1_000_000 # 返回毫秒级精确时间 else: # 在实际应用中应使用RDTSC指令 return time.process_time() * 1000 def create_power_model(self): # 简化的线性模型: P = a * utilization + b return lambda u: 15 + 85 * (u/100) # 基础功耗15W + 动态功耗 def estimate_energy(self, physical_time): utilization = self.get_cpu_utilization(physical_time) power = self.power_model(utilization) # 当前功耗(W) time_seconds = physical_time / 1000 # 换为秒 return power * time_seconds # 能耗(J) class TimerApp: """计时器应用GUI""" def __init__(self, root): self.root = root root.title("高精度计时器 - 专业版") root.geometry("900x700") root.resizable(True, True) # 创建两种计时器实例 self.performance_timer = PerformanceCounterTimer() self.cpu_cycle_timer = CPUCycleTimer() # 当前选中的计时方案 self.current_timer = self.performance_timer self.interrupt_monitor_running = False # 计时记录列表 self.time_records = [] # 创建UI self.create_widgets() # 性能优化计数器 self.update_count = 0 # 启动UI更新循环 self.update_display() # 启动中断监控线程 self.start_interrupt_monitor() def create_widgets(self): """创建界面组件""" # 主框架 main_frame = tk.Frame(self.root) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 左侧控制面板 control_frame = tk.Frame(main_frame) control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5) # 方案选择 mode_frame = tk.LabelFrame(control_frame, text="计时方案", padx=10, pady=10) mode_frame.pack(fill=tk.X, pady=5) self.mode_var = tk.StringVar(value="performance") modes = [("性能计数器 (物理时间)", "performance"), ("CPU周期 (CPU时间)", "cpu")] for text, mode in modes: rb = tk.Radiobutton(mode_frame, text=text, variable=self.mode_var, value=mode, command=self.switch_mode) rb.pack(anchor=tk.W, padx=5, pady=2) # 控制按钮 btn_frame = tk.Frame(control_frame) btn_frame.pack(fill=tk.X, pady=10) self.start_btn = tk.Button(btn_frame, text="开始", width=12, command=self.start_stop) self.start_btn.pack(side=tk.LEFT, padx=5) reset_btn = tk.Button(btn_frame, text="重置", width=12, command=self.reset) reset_btn.pack(side=tk.LEFT, padx=5) # 记录按钮 self.record_btn = tk.Button(btn_frame, text="记录本次", width=12, command=self.record_current, state=tk.DISABLED) self.record_btn.pack(side=tk.LEFT, padx=5) # 统计按钮 stats_btn = tk.Button(btn_frame, text="生成报告", width=12, command=self.generate_report) stats_btn.pack(side=tk.LEFT, padx=5) # CPU信息 info_frame = tk.LabelFrame(control_frame, text="系统信息", padx=10, pady=10) info_frame.pack(fill=tk.X, pady=5) cpu_freq = self.cpu_cycle_timer.frequency freq_text = f"CPU频率: {cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"CPU频率: {cpu_freq/1e6:.0f} MHz" self.cpu_label = tk.Label(info_frame, text=freq_text, justify=tk.LEFT) self.cpu_label.pack(anchor=tk.W) cores_text = f"CPU核心数: {os.cpu_count()}" tk.Label(info_frame, text=cores_text, justify=tk.LEFT).pack(anchor=tk.W) # 中断统计 interrupt_frame = tk.LabelFrame(control_frame, text="中断统计", padx=10, pady=10) interrupt_frame.pack(fill=tk.X, pady=5) self.interrupt_label = tk.Label(interrupt_frame, text="中断次数: 0") self.interrupt_label.pack(anchor=tk.W) # 右侧数据显示 display_frame = tk.Frame(main_frame) display_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 双模式时间显示 time_frame = tk.LabelFrame(display_frame, text="时间显示", padx=10, pady=10) time_frame.pack(fill=tk.X, pady=5) # 物理时间显示 - 添加颜色(蓝色) physical_frame = tk.Frame(time_frame) physical_frame.pack(fill=tk.X, pady=5) tk.Label(physical_frame, text="物理时间:", width=10).pack(side=tk.LEFT) self.physical_label = tk.Label(physical_frame, text="00:00:00.000", font=("Consolas", 12), fg="blue") self.physical_label.pack(side=tk.LEFT) # CPU时间显示 - 添加颜色(红色) cpu_frame = tk.Frame(time_frame) cpu_frame.pack(fill=tk.X, pady=5) tk.Label(cpu_frame, text="CPU时间:", width=10).pack(side=tk.LEFT) self.cpu_time_label = tk.Label(cpu_frame, text="00:00:00.000", font=("Consolas", 12), fg="red") self.cpu_time_label.pack(side=tk.LEFT) # 计时记录框架 records_frame = tk.LabelFrame(display_frame, text="计时记录", padx=10, pady=10) records_frame.pack(fill=tk.X, pady=5) # 创建记录表格 columns = ("序号", "标签", "物理时间", "CPU时间", "差值") self.records_tree = ttk.Treeview(records_frame, columns=columns, show="headings", height=5) # 设置列标题 for col in columns: self.records_tree.heading(col, text=col) self.records_tree.column(col, width=80, anchor=tk.CENTER) # 设置列宽 self.records_tree.column("标签", width=120) # 添加滚动条 scrollbar = ttk.Scrollbar(records_frame, orient="vertical", command=self.records_tree.yview) self.records_tree.configure(yscrollcommand=scrollbar.set) self.records_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 统计图表 chart_frame = tk.LabelFrame(display_frame, text="计时统计图", padx=10, pady=10) chart_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 创建图表 self.figure, self.ax = plt.subplots(figsize=(8, 4)) self.canvas = FigureCanvasTkAgg(self.figure, chart_frame) self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) # 初始化图表 self.update_chart() def switch_mode(self): """切换计时方案""" selected = self.mode_var.get() if selected == "performance": self.current_timer = self.performance_timer else: self.current_timer = self.cpu_cycle_timer # 更新CPU频率显示 cpu_freq = self.cpu_cycle_timer.frequency freq_text = f"CPU频率: {cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"CPU频率: {cpu_freq/1e6:.0f} MHz" self.cpu_label.config(text=freq_text) def start_stop(self): """开始/停止计时 - 只操作当前选中的计时器""" if self.current_timer.running: self.current_timer.stop() self.start_btn.config(text="开始") self.record_btn.config(state=tk.DISABLED) else: # 只启动当前选中的计时器 self.current_timer.start() self.start_btn.config(text="停止") self.record_btn.config(state=tk.NORMAL) def record_current(self): """记录当前计时值""" if self.current_timer.running: # 获取当前两种计时器的值 physical_ms = self.performance_timer.current_elapsed() cpu_ms = self.cpu_cycle_timer.current_elapsed() # 创建记录 record = { "id": len(self.time_records) + 1, "label": f"记录 {len(self.time_records) + 1}", "physical": physical_ms, "cpu": cpu_ms, "difference": abs(physical_ms - cpu_ms) } # 添加到记录列表 self.time_records.append(record) # 更新表格 self.update_records_table() # 更新图表 self.update_chart() def update_records_table(self): """更新计时记录表格""" # 清空现有数据 for item in self.records_tree.get_children(): self.records_tree.delete(item) # 添加新记录 for record in self.time_records: self.records_tree.insert("", "end", values=( record["id"], record["label"], f"{record['physical']:.1f} ms", f"{record['cpu']:.1f} ms", f"{record['difference']:.1f} ms" )) def update_chart(self): """更新计时统计图表""" self.ax.clear() if self.time_records: # 准备数据 labels = [r["label"] for r in self.time_records] physical_times = [r["physical"] for r in self.time_records] cpu_times = [r["cpu"] for r in self.time_records] x = np.arange(len(labels)) width = 0.35 # 绘制柱状图 rects1 = self.ax.bar(x - width/2, physical_times, width, label='物理时间', color='blue') rects2 = self.ax.bar(x + width/2, cpu_times, width, label='CPU时间', color='red') # 添加标签、标题等 self.ax.set_ylabel('时间 (ms)') self.ax.set_title('计时记录对比') self.ax.set_xticks(x) self.ax.set_xticklabels(labels) self.ax.legend() # 添加数值标签 self.ax.bar_label(rects1, padding=3, fmt='%.1f') self.ax.bar_label(rects2, padding=3, fmt='%.1f') # 调整布局 self.figure.tight_layout() else: # 没有记录时显示提示信息 self.ax.text(0.5, 0.5, '暂无计时记录', horizontalalignment='center', verticalalignment='center', transform=self.ax.transAxes, fontsize=14) self.canvas.draw() def reset(self): """重置当前计时器""" self.current_timer.reset() self.start_btn.config(text="开始") self.record_btn.config(state=tk.DISABLED) # 更新显示 self.update_display() def start_interrupt_monitor(self): """启动中断监控线程""" if not self.interrupt_monitor_running: self.interrupt_monitor_running = True threading.Thread(target=self.monitor_interrupts, daemon=True).start() def monitor_interrupts(self): """模拟中断监控""" while self.interrupt_monitor_running: time.sleep(0.1) # 在实际应用中,这里应读取系统中断计数器 if self.current_timer.running: # 模拟随机中断 if np.random.random() < 0.02: # 2%概率发生中断 self.performance_timer.record_interrupt() self.cpu_cycle_timer.record_interrupt() self.root.after(0, self.update_interrupt_count) def update_interrupt_count(self): """更新中断计数显示""" count = self.performance_timer.interrupt_count self.interrupt_label.config(text=f"中断次数: {count}") def generate_report(self): """生成详细分析报告并保存为CSV文件""" filename = f"timer_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" with open(filename, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) # 写入报告头部信息 writer.writerow(["高精度计时器分析报告"]) writer.writerow(["生成时间", datetime.now().strftime("%Y-%m-%d %H:%M:%S")]) writer.writerow([]) # 写入系统信息 writer.writerow(["系统信息"]) writer.writerow(["操作系统", platform.platform()]) writer.writerow(["CPU核心数", os.cpu_count()]) cpu_freq = self.cpu_cycle_timer.frequency freq_text = f"{cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"{cpu_freq/1e6:.0f} MHz" writer.writerow(["CPU频率", freq_text]) writer.writerow(["Python版本", sys.version]) writer.writerow([]) # 格式化时间函数 def format_ms(ms): hours, rem = divmod(ms, 3600000) minutes, rem = divmod(rem, 60000) seconds, milliseconds = divmod(rem, 1000) return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}.{int(milliseconds):03d}" # 写入时间指标 physical_time = self.performance_timer.total_elapsed cpu_time = self.cpu_cycle_timer.total_elapsed wait_time = max(0, physical_time - cpu_time) # 系统等待时间 writer.writerow(["时间指标"]) writer.writerow(["度量项", "数值(毫秒)", "格式化时间"]) writer.writerow(["物理时间", f"{physical_time:.3f}", format_ms(physical_time)]) writer.writerow(["CPU时间", f"{cpu_time:.3f}", format_ms(cpu_time)]) writer.writerow(["系统等待时间", f"{wait_time:.3f}", format_ms(wait_time)]) writer.writerow([]) # 写入性能指标 utilization = self.cpu_cycle_timer.get_cpu_utilization(physical_time) if physical_time > 0 else 0 energy = self.cpu_cycle_timer.estimate_energy(physical_time) if physical_time > 0 else 0 writer.writerow(["性能指标"]) writer.writerow(["CPU利用率", f"{utilization:.2f}%"]) writer.writerow(["系统中断次数", self.performance_timer.interrupt_count]) writer.writerow(["估算能耗", f"{energy:.2f} J"]) writer.writerow([]) # 写入计时记录 writer.writerow(["计时记录"]) writer.writerow(["序号", "标签", "物理时间(ms)", "CPU时间(ms)", "差值(ms)"]) for i, record in enumerate(self.time_records, 1): writer.writerow([ i, record["label"], f"{record['physical']:.3f}", f"{record['cpu']:.3f}", f"{abs(record['physical'] - record['cpu']):.3f}" ]) writer.writerow([]) # 添加数学公式注解 writer.writerow(["计算公式注解"]) writer.writerow(["CPU利用率", r"$\eta = \frac{T_{cpu}}{T_{physical}} \times 100\%$"]) writer.writerow(["系统等待时间", r"$\Delta t = T_{physical} - T_{cpu}$"]) writer.writerow(["能耗估算", r"$E = \int_{0}^{T} P(u(t)) \, dt$", "(P=功耗模型)"]) # 显示成功消息 tk.messagebox.showinfo("报告生成", f"分析报告已保存至:\n{os.path.abspath(filename)}") def update_display(self): """更新UI显示""" # 获取两个计时器的当前时间 physical_ms = self.performance_timer.current_elapsed() cpu_ms = self.cpu_cycle_timer.current_elapsed() # 格式化时间 physical_str = self.ms_to_time_str(physical_ms) cpu_str = self.ms_to_time_str(cpu_ms) # 始终更新两个时间显示 self.physical_label.config(text=physical_str) self.cpu_time_label.config(text=cpu_str) # 计算性能指标 if physical_ms > 0: utilization = min(100, max(0, (cpu_ms / physical_ms) * 100)) wait_time = max(0, physical_ms - cpu_ms) energy = self.cpu_cycle_timer.estimate_energy(physical_ms) else: utilization = 0 wait_time = 0 energy = 0 # 更新性能指标显示 self.util_label.config(text=f"{utilization:.1f}%") self.wait_label.config(text=f"{wait_time:.1f} ms") self.energy_label.config(text=f"{energy:.1f} J") # 每100毫秒更新一次显示 self.root.after(100, self.update_display) def ms_to_time_str(self, ms): """将毫秒数格式化为 HH:MM:SS.ms 字符串""" ms = max(0, ms) # 确保非负 seconds, milliseconds = divmod(ms, 1000) minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}.{int(milliseconds):03d}" if ms > 0 else "00:00:00.000" def __del__(self): """清理资源""" self.interrupt_monitor_running = False if __name__ == "__main__": root = tk.Tk() app = TimerApp(root) try: root.mainloop() finally: # 确保线程安全退出 app.interrupt_monitor_running = False [Running] python -u "e:\system\Desktop\项目所需文件\工具\计时器工具\timer copy 2.py" Traceback (most recent call last): File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 567, in <module> app = TimerApp(root) ^^^^^^^^^^^^^^ File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 182, in __init__ self.update_display() File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 546, in update_display self.util_label.config(text=f"{utilization:.1f}%") ^^^^^^^^^^^^^^^ AttributeError: 'TimerApp' object has no attribute 'util_label'
最新发布
10-14
<think>我们遇到了一个AttributeError: 'TimerApp' object has no attribute 'util_label'的错误。这是因为在更新显示时,我们试图访问util_label,但在UI中我们并没有创建这个标签。 回顾代码,在之前的版本中我们删除了时间分解分析的部分,其中包括util_label、wait_label和energy_label。但是在update_display方法中,我们仍然尝试更新这些标签。 因此,我们需要做以下两件事之一: 1. 重新添加时间分解分析的部分(包含util_label, wait_label, energy_label)以便更新这些标签。 2. 从update_display方法中移除对这些标签的更新。 但是,根据用户之前的要求:“时间分解分析及多喝利用率热力图没有任何实际作用需要删除”,我们删除了这些部分。因此,现在我们应该选择第二种方案: 在update_display方法中,删除对util_label、wait_label、energy_label的更新代码。 然而,在查看当前代码中的create_widgets方法时,我们发现确实没有创建这些标签。所以,我们需要修改update_display方法,去掉这些标签的更新。 另外,我们注意到在update_display方法中,我们尝试显示性能指标(CPU利用率、系统等待时间、能耗估算),但这些指标在UI上已经没有对应的标签了。所以,我们应该将这些计算和显示移除。 但是,请注意:用户可能仍然希望看到这些指标?不过根据最初的要求,是要求删除时间分解分析及热力图,所以我们删除了整个框架。因此,这些指标没有地方显示,所以不应该计算。 然而,在生成报告时,我们仍然需要这些指标(报告生成函数中用到了)。所以计算本身可以保留,但UI显示部分需要移除。 因此,修改update_display方法:移除对util_label、wait_label、energy_label的更新。 但是,在查看代码中的create_widgets方法,我们发现在右侧数据显示部分,已经没有这些标签了。所以只需删除update_display中更新这些标签的代码即可。 修改update_display方法,删除以下部分: # 更新性能指标显示 self.util_label.config(text=f"{utilization:.1f}%") self.wait_label.config(text=f"{wait_time:.1f} ms") self.energy_label.config(text=f"{energy:.1f} J") 同时,我们注意到在update_display方法中,我们仍然计算了utilization, wait_time, energy,但计算后没有使用。由于报告生成需要,计算可以保留,但如果不用于显示,也可以不计算。但是,为了报告生成时能直接使用,我们最好保留计算。不过,每次更新显示都计算这些值可能会增加开销,而且报告生成时我们可以重新计算,所以这里可以去掉计算部分。 但是,注意报告生成函数中已经独立计算了这些值,并不依赖于update_display中的计算结果。因此,我们可以安全地移除update_display中的计算代码。 因此,我们将在update_display中移除计算和更新这些标签的代码。 另外,我们注意到在update_display方法中,我们更新了物理时间和CPU时间的显示,这部分保留。 修改后的update_display方法如下: def update_display(self): """更新UI显示""" # 获取两个计时器的当前时间 physical_ms = self.performance_timer.current_elapsed() cpu_ms = self.cpu_cycle_timer.current_elapsed() # 格式化时间 physical_str = self.ms_to_time_str(physical_ms) cpu_str = self.ms_to_time_str(cpu_ms) # 始终更新两个时间显示 self.physical_label.config(text=physical_str) self.cpu_time_label.config(text=cpu_str) # 每100毫秒更新一次显示 self.root.after(100, self.update_display) 但这样修改后,中断次数显示在哪里?在create_widgets方法中,我们创建了中断统计的标签(interrupt_label),并在update_interrupt_count方法中更新它。这个标签还存在,所以中断次数的更新是正常的。 所以,我们只需要删除update_display中关于性能指标的计算和更新即可。 但是,我们注意到在update_display方法中,我们并没有更新中断次数。中断次数是通过另一个线程在检测到中断时通过after方法调用update_interrupt_count来更新的。所以,中断次数的更新与update_display无关。 因此,我们按照上述修改update_display方法。 另外,在generate_report方法中,我们使用了以下计算: utilization = self.cpu_cycle_timer.get_cpu_utilization(physical_time) if physical_time > 0 else 0 energy = self.cpu_cycle_timer.estimate_energy(physical_time) if physical_time > 0 else 0 注意,这里的utilization和energy都是基于两个计时器的总时间(total_elapsed)计算的,并不是update_display中计算的值。所以,报告生成是独立的,不受影响。 因此,我们修改update_display方法,去掉不必要的计算和更新。 但是,我们注意到在create_widgets方法中,我们并没有删除性能指标的显示标签?实际上,在之前的重构中,我们删除了整个时间分解分析框架,所以util_label等标签已经不存在了。因此,我们只需确保update_display中不再引用这些标签即可。 现在,让我们修改代码中的update_display方法。 另外,我们还需要检查一下,在create_widgets方法中,确实没有创建util_label、wait_label、energy_label。通过阅读代码,在当前的create_widgets方法中,我们只创建了以下标签: - physical_label(物理时间) - cpu_time_label(CPU时间) - interrupt_label(中断次数) - 以及记录表格和图表 所以,我们只需修改update_display方法。 修改如下: def update_display(self): """更新UI显示""" # 获取两个计时器的当前时间 physical_ms = self.performance_timer.current_elapsed() cpu_ms = self.cpu_cycle_timer.current_elapsed() # 格式化时间 physical_str = self.ms_to_time_str(physical_ms) cpu_str = self.ms_to_time_str(cpu_ms) # 始终更新两个时间显示 self.physical_label.config(text=physical_str) self.cpu_time_label.config(text=cpu_str) # 每100毫秒更新一次显示 self.root.after(100, self.update_display) 这样,去掉了性能指标的计算和更新,避免了属性错误。 另外,我们还需要注意:在记录当前计时值(record_current)时,我们同时记录了物理时间和CPU时间,并更新了表格和图表,这部分是正常的。 现在,我们修正代码并重新运行。 但是,为了确保安全,我们还需要检查一下,在生成报告时,是否还使用了update_display中计算的其他值?没有,因为报告生成函数中重新计算了所有需要的值。 因此,我们进行上述修改。 注意:由于代码较长,我将只提供修改后的update_display方法,并替换原代码中的对应方法。 修改后的完整代码(仅update_display方法修改): </think>这个错误是因为在 `TimerApp` 类的 `create_widgets` 方法中,您删除了显示性能指标(CPU利用率、系统等待时间、能耗估算)的UI元素,但在 `update_display` 方法中仍然尝试更新这些不存在的UI元素。 ### 错误原因分析: 1. 在原始代码中,`create_widgets` 方法创建了 `util_label`、`wait_label` 和 `energy_label` 这些UI元素 2. 在新版本的代码中,这些UI元素被移除了 3. 但 `update_display` 方法中仍然尝试更新这些不存在的UI元素: ```python # 更新性能指标显示 self.util_label.config(text=f"{utilization:.1f}%") self.wait_label.config(text=f"{wait_time:.1f} ms") self.energy_label.config(text=f"{energy:.1f} J") ``` ### 解决方法: 删除 `update_display` 方法中更新性能指标的部分,因为这些UI元素已被移除。以下是修正后的 `update_display` 方法: ```python def update_display(self): """更新UI显示""" # 获取两个计时器的当前时间 physical_ms = self.performance_timer.current_elapsed() cpu_ms = self.cpu_cycle_timer.current_elapsed() # 格式化时间 physical_str = self.ms_to_time_str(physical_ms) cpu_str = self.ms_to_time_str(cpu_ms) # 始终更新两个时间显示 self.physical_label.config(text=physical_str) self.cpu_time_label.config(text=cpu_str) # 每100毫秒更新一次显示 self.root.after(100, self.update_display) ``` ### 完整修正代码: ```python import tkinter as tk from tkinter import ttk import time import sys import os import platform import ctypes import csv import threading import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from ctypes import windll, wintypes from collections import defaultdict from datetime import datetime # 解决中文警告问题 import matplotlib as mpl mpl.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] # 指定默认字体 mpl.rcParams['axes.unicode_minus'] = False # 解决负号显示问题 class HighPrecisionTimer: """高精度计时器基类""" def __init__(self): self.start_time = 0 self.total_elapsed = 0 self.running = False self.interrupt_count = 0 # 中断计数器 self.records = [] # 记录每次计时结果 def start(self): """开始计时""" if not self.running: self.start_time = self.current_time() self.running = True def stop(self): """停止计时""" if self.running: elapsed = self.current_time() - self.start_time self.total_elapsed += elapsed self.running = False def reset(self): """重置计时器""" self.total_elapsed = 0 self.running = False self.interrupt_count = 0 self.records = [] def current_elapsed(self): """获取当前已过时间(毫秒)""" if self.running: return self.total_elapsed + (self.current_time() - self.start_time) return self.total_elapsed def current_time(self): """抽象方法,由子类实现具体计时方案""" raise NotImplementedError("Subclasses must implement current_time()") def record_current(self): """记录当前计时值""" if self.running: elapsed = self.current_elapsed() self.records.append({ "timestamp": datetime.now(), "elapsed": elapsed, "label": f"记录 {len(self.records)+1}" }) return elapsed return 0 def get_cpu_utilization(self, physical_time): if physical_time > 0: return min(100, max(0, (self.current_elapsed() / physical_time) * 100)) return 0 def record_interrupt(self): """记录中断事件""" self.interrupt_count += 1 class PerformanceCounterTimer(HighPrecisionTimer): """基于性能计数器的物理计时方案""" def __init__(极寒行者"): super().__init__() # 获取性能计数器频率 if platform.system() == 'Windows': self.frequency = ctypes.c_int64() windll.kernel32.QueryPerformanceFrequency(ctypes.byref(self.frequency)) self.frequency = self.frequency.value else: # Linux/macOS使用time.perf_counter self.frequency = 1e9 # 1秒 = 1e9纳秒 def current_time(self): """获取当前性能计数器时间(毫秒)""" if platform.system() == 'Windows': counter = ctypes.c极寒行者") windll.kernel32.QueryPerformanceCounter(ctypes.byref(counter)) return (counter.value * 1000) / self.frequency # 换为毫秒 else: # 跨平台方案 return time.perf_counter() * 1000 class CPUCycleTimer(HighPrecisionTimer): """基于CPU周期的计时方案""" def __init__(self): super().__init__() # 获取CPU频率 self.frequency = self.get_cpu_frequency() self.power_model = self.create_power_model() # 创建功耗模型 def get_cpu_frequency(self): """尝试获取CPU频率""" try: if platform.system() == 'Windows': # Windows获取CPU频率 import winreg key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\CentralProcessor\0") value, _ = winreg.QueryValueEx(key, "~MHz") winreg.CloseKey(key) return value * 1e6 # MHz换为Hz else: # Linux/macOS获取CPU频率 with open('/proc/cpuinfo') as f: for line in f: if 'cpu MHz' in line: return float(line.split(':')[1].strip()) * 1e6 # 默认值 return 3.5e9 # 3.5 GHz except: return 3.5e9 # 3.5 GHz def current_time(self): """获取当前CPU周期计数并换为毫秒""" if platform.system() == 'Windows': return time.perf_counter_ns() / 1_000_000 # 返回毫秒级精确时间 else: # 在实际应用中应使用RDTSC指令 return time.process_time() * 1000 def create_power_model(self): # 简化的线性模型: P = a * utilization + b return lambda u: 15 + 85 * (u/100) # 基础功耗15W + 动态功耗 def estimate_energy(self, physical_time): utilization = self.get_cpu_utilization(physical_time) power = self.power_model(utilization) # 当前功耗(W) time_seconds = physical_time / 1000 # 换为秒 return power * time_seconds # 能耗(J) class TimerApp: """计时器应用GUI""" def __init__(self, root): self.root = root root.title("高精度计时器 - 专业版") root.geometry("900x700") root.resizable(True, True) # 创建两种计时器实例 self.performance_timer = PerformanceCounterTimer() self.cpu_cycle_timer = CPUCycleTimer() # 当前选中的计时方案 self.current_timer = self.performance_timer self.interrupt_monitor_running = False # 计时记录列表 self.time_records = [] # 创建UI self.create_widgets() # 启动UI更新循环 self.update_display() # 启动中断监控线程 self.start_interrupt_monitor() def create_widgets(self): """创建界面组件""" # 主框架 main_frame = tk.Frame(self.root) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 左侧控制面板 control_frame = tk.Frame(main_frame) control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5) # 方案选择 mode_frame = tk.LabelFrame(control_frame, text="计时方案", padx=10, pady=10) mode_frame.pack(fill=tk.X, pady=5) self.mode_var = tk.StringVar(value="performance") modes = [("性能计数器 (物理时间)", "performance"), ("CPU周期 (CPU时间)", "cpu")] for text, mode in modes: rb = tk.Radiobutton(mode_frame, text=text, variable=self.mode_var, value=mode, command=self.switch_mode) rb.pack(anchor=tk.W, padx=5, pady=2) # 控制按钮 btn_frame = tk.Frame(control_frame) btn_frame.pack(f极寒行者") self.start_btn = tk.Button(btn_frame, text="开始", width=12, command=self.start_stop) self.start_btn.pack(side=tk.LEFT, padx=5) reset_btn = tk.Button(btn_frame, text="重置", width=12, command=self.reset) reset_btn.pack(side=tk.LEFT, padx=5) # 记录按钮 self.record_btn = tk.Button(btn_frame, text="记录本次", width=12, command=self.record_current, state=tk.DISABLED) self.record_btn.pack(side=tk.LEFT, padx=5) # 统计按钮 stats_btn = tk.Button(btn_frame, text="生成报告", width=12, command=self.generate_report) stats_btn.pack(side=tk.LEFT, padx=5) # CPU信息 info_frame = tk.LabelFrame(control_frame, text="系统信息", padx=10, pady=10) info_frame.pack(fill=tk.X, pady=5) cpu_freq = self.cpu_cycle_timer.frequency freq_text = f"CPU频率: {cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"CPU频率: {cpu_freq/1e6:.0f} MHz" self.cpu_label = tk.Label(info_frame, text=freq_text, justify=tk.LEFT) self.cpu_label.pack(anchor=tk.W) cores_text = f"CPU核心数: {os.cpu_count()}" tk.Label(info_frame, text=cores_text, justify=tk.LEFT).pack(anchor=tk.W) # 中断统计 interrupt_frame = tk.LabelFrame(control_frame, text="中断统计", padx=10, pady=10) interrupt_frame.pack(fill=tk.X, pady=5) self.interrupt_label = tk.Label(interrupt_frame, text="中断次数: 0") self.interrupt_label.pack(anchor=tk.W) # 右侧数据显示 display_frame = tk.Frame(main_frame) display_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 双模式时间显示 time_frame = tk.LabelFrame(display_frame, text="时间显示", padx=10, pady=10) time_frame.pack(fill=tk.X, pady=5) # 物理时间显示 - 添加颜色(蓝色) physical_frame = tk.Frame(time_frame) physical_frame.pack(fill=tk.X, pady=5) tk.Label(physical_frame, text="物理时间:", width=10).pack(side=tk.LEFT) self.physical_label = tk.Label(physical_frame, text="00:00:00.000", font=("Consolas", 12), fg="blue") self.physical_label.pack(side=tk.LEFT) # CPU时间显示 - 添加颜色(红色) cpu_frame = tk.Frame(time_frame) cpu_frame.pack(fill=tk.X, pady=5) tk.Label(cpu_frame, text="CPU时间:", width=10).pack(side=tk.LEFT) self.cpu_time_label = tk.Label(cpu_frame, text="00:00:00.000", font=("Consolas", 12), f极寒行者") self.cpu_time_label.pack(side=tk.LEFT) # 计时记录框架 records_frame = tk.LabelFrame(display_frame, text="计时记录", padx=10, pady=10) records_frame.pack(fill=tk.X, pady=5) # 创建记录表格 columns = ("序号", "标签", "物理时间", "CPU时间", "差值") self.records_tree = ttk.Treeview(records_frame, columns=columns, show="headings", height=5) # 设置列标题 for col in columns: self.records_tree.heading(col, text=col) self.records_tree.column(col, width=80, anchor=tk.CENTER) # 设置列宽 self.records_tree.column("标签", width=120) # 添加滚动条 scrollbar = ttk.Scrollbar(records_frame, orient="vertical", command=self.records_tree.yview) self.records_tree.configure(yscrollcommand=scrollbar.set) self.records_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 统计图表 chart_frame = tk.LabelFrame(display_frame, text="计时统计图", padx=10, pady=10) chart_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 创建图表 self.figure, self.ax = plt.subplots(figsize=(8, 4)) self.canvas = FigureCanvasTkAgg(self.figure, chart_frame) self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) # 初始化图表 self.update_chart() def switch_mode(self): """切换计时方案""" selected = self.mode_var.get() if selected == "performance": self.current_timer = self.performance_timer else: self.current_timer = self.cpu_cycle_timer # 更新CPU频率显示 cpu_freq = self.cpu_cycle_timer.frequency freq_text = f"CPU频率: {cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"CPU频率: {cpu_freq/1e6:.0f} MHz" self.cpu_label.config(text=freq_text) def start_stop(self): """开始/停止计时 - 只操作当前选中的计时器""" if self.current_timer.running: self.current_timer.stop() self.start_btn.config(text="开始") self.record_btn.config(state=tk.DISABLED) else: # 只启动当前选中的计时器 self.current_timer.start() self.start_btn.config(text="停止") self.record_btn.config(state=tk.NORMAL) def record_current(self): """记录当前计时值""" if self.current_timer.running: # 获取当前两种计时器的值 physical_ms = self.performance_timer.current_elapsed() cpu_ms = self.cpu_cycle_timer.current_elapsed() # 创建记录 record = { "id": len(self.time_records) + 1, "label": f"记录 {len(self.time_records) + 1}", "physical": physical_ms, "cpu": cpu_ms, "difference": abs(physical_ms - cpu_ms) } # 添加到记录列表 self.time_records.append(record) # 更新表格 self.update_records_table() # 更新图表 self.update_chart() def update_records_table(self): """更新计时记录表格""" # 清空现有数据 for item in self.records_tree.get_children(): self.records_tree.delete(item) # 添加新记录 for record in self.time_records: self.records_tree.insert("", "end", values=( record["id"], record["label"], f"{record['physical']:.1f} ms", f"{record['cpu']:.1f} ms", f"{record['difference']:.1f} ms" )) def update_chart(self): """更新计时统计图表""" self.ax.clear() if self.time_records: # 准备数据 labels = [r["label"] for r in self.time_records] physical_times = [r["physical"] for r in self.time_records] cpu_times = [r["cpu"] for r in self.time_records] x = np.arange(len(labels)) width = 0.35 # 绘制柱状图 rects1 = self.ax.bar(x - width/2, physical_times, width, label='物理时间', color='blue') rects2 = self.ax.bar(x + width/2, cpu_times, width, label='CPU时间', color='
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值