class SingleButtonDialog(NeVerDialog): """ This class is a generic dialog with a single button at the bottom of the main layout. It also provides a method for imposing the button text ('Ok' by default) Attributes ---------- button : CustomButton A single button for leaving the dialog Methods ---------- set_button_text(str) A method for setting the button text """ def __init__(self, title: str = 'NeVer Dialog', message: str = ''): super(SingleButtonDialog, self).__init__(title, message) self.button = CustomButton('Ok') self.button.clicked.connect(self.close) def set_button_text(self, text: str): self.button.setText(text) def render_layout(self) -> None: """ Override with a button at the end """ self.layout.addWidget(self.button) self.setLayout(self.layout)
def __init__(self, nn: NeuralNetwork, properties: dict): super().__init__("Verify network") self.nn = nn self.properties = properties self.strategy = None self.params = utility.read_json(ROOT_DIR + '/res/json/verification.json') def activation_cb(methodology: str): return lambda: self.update_methodology(self.widgets[ "Verification methodology"].currentText()) body_layout = self.create_widget_layout(self.params, cb_f=activation_cb) self.layout.addLayout(body_layout) # Buttons btn_layout = QHBoxLayout() self.verify_btn = CustomButton("Verify network") self.verify_btn.clicked.connect(self.verify_network) self.cancel_btn = CustomButton("Cancel") self.cancel_btn.clicked.connect(self.close) btn_layout.addWidget(self.verify_btn) btn_layout.addWidget(self.cancel_btn) self.layout.addLayout(btn_layout) self.render_layout()
def __init__(self, title: str = 'NeVer Dialog', message: str = ''): super(TwoButtonsDialog, self).__init__(title, message) self.cancel_btn = CustomButton('Cancel') self.cancel_btn.clicked.connect(self.close) self.ok_btn = CustomButton('Ok') self.ok_btn.clicked.connect(self.close) self.button_layout = QHBoxLayout() self.button_layout.addWidget(self.cancel_btn) self.button_layout.addWidget(self.ok_btn)
def __init__(self, node_block: NodeBlock): super().__init__(node_block.node.name, "") self.layout = QGridLayout() # Connect node self.node = node_block self.parameters = dict() self.edited_data = dict() self.has_edits = False # Build main_layout title_label = CustomLabel("Edit parameters") title_label.setStyleSheet(style.NODE_LABEL_STYLE) title_label.setAlignment(Qt.AlignCenter) self.layout.addWidget(title_label, 0, 0, 1, 2) # Input box in_dim_label = CustomLabel("Input") in_dim_label.setStyleSheet(style.IN_DIM_LABEL_STYLE) in_dim_label.setAlignment(Qt.AlignRight) self.layout.addWidget(in_dim_label, 1, 0) in_dim_box = CustomTextBox(','.join(map(str, node_block.in_dim))) in_dim_box.setValidator(ArithmeticValidator.TENSOR) self.layout.addWidget(in_dim_box, 1, 1) self.parameters["in_dim"] = in_dim_box if not node_block.is_head: in_dim_box.setReadOnly(True) # Display parameters if present counter = 2 if node_block.node.param: counter = self.append_node_params(node_block.node, node_block.block_data) # "Apply" button which saves changes apply_button = CustomButton("Apply") apply_button.clicked.connect(self.save_data) self.layout.addWidget(apply_button, counter, 0) # "Cancel" button which closes the dialog without saving cancel_button = CustomButton("Cancel") cancel_button.clicked.connect(self.close) self.layout.addWidget(cancel_button, counter, 1) self.layout.setColumnStretch(0, 1) self.layout.setColumnStretch(1, 1) self.render_layout()
class TwoButtonsDialog(NeVerDialog): """ This class is a generic dialog with two buttons at the bottom of the main layout, for accepting or refusing the operations of the dialog. It also provides a method for imposing the buttons text ('Cancel' and 'Ok' by default) Attributes ---------- cancel_btn : CustomButton A single button for leaving the dialog without applying the changes ok_btn : CustomButton A single button for leaving the dialog and applying the changes Methods ---------- set_buttons_text(str, str) A method for setting the buttons text """ def __init__(self, title: str = 'NeVer Dialog', message: str = ''): super(TwoButtonsDialog, self).__init__(title, message) self.cancel_btn = CustomButton('Cancel') self.cancel_btn.clicked.connect(self.close) self.ok_btn = CustomButton('Ok') self.ok_btn.clicked.connect(self.close) self.button_layout = QHBoxLayout() self.button_layout.addWidget(self.cancel_btn) self.button_layout.addWidget(self.ok_btn) def set_buttons_text(self, cancel_text: str, ok_text: str): self.cancel_btn.setText(cancel_text) self.ok_btn.setText(ok_text) def render_layout(self) -> None: """ Override with a button at the end """ self.layout.addLayout(self.button_layout) self.setLayout(self.layout)
def __init__(self, name: str, parameters: dict): super().__init__() self.layout = QVBoxLayout() self.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) self.setStyleSheet(style.DROPDOWN_STYLE) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) # Top bar with short info self.top = QWidget() self.top.setContentsMargins(0, 0, 0, 0) self.top.setStyleSheet(style.DROPDOWN_TOP_STYLE) self.top_layout = QHBoxLayout() self.top_layout.setContentsMargins(0, 0, 0, 0) self.top.setLayout(self.top_layout) self.name_label = CustomLabel(name) self.name_label.setAlignment(Qt.AlignLeft) self.name_label.setStyleSheet(style.DROPDOWN_NAME_STYLE) self.top_layout.addWidget(self.name_label, Qt.AlignLeft) self.type_label = CustomLabel(parameters["type"]) self.type_label.setAlignment(Qt.AlignLeft) self.type_label.setToolTip("Type") self.type_label.setStyleSheet(style.DROPDOWN_TYPE_STYLE) self.top_layout.addWidget(self.type_label, Qt.AlignLeft) if "default" in parameters: self.default_label = CustomLabel(parameters["default"]) self.default_label.setStyleSheet(style.DROPDOWN_DEFAULT_STYLE) self.default_label.setToolTip("Default value") self.default_label.setAlignment(Qt.AlignCenter) self.top_layout.addWidget(self.default_label, Qt.AlignRight) self.down_button = CustomButton("\u25bc") self.down_button.setStyleSheet(style.DROPDOWN_ARROW_STYLE) self.down_button.clicked.connect(lambda: self.__toggle_visibility()) self.top_layout.addWidget(self.down_button, Qt.AlignRight) self.layout.addWidget(self.top) self.description = CustomLabel(parameters["description"]) self.description.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) self.description.setWordWrap(True) self.description.setStyleSheet(style.DESCRIPTION_STYLE) self.description.hide() self.layout.addWidget(self.description)
def __init__(self, node_block: NodeBlock): super().__init__(node_block.node.name, "") self.layout = QGridLayout() # Connect node self.node = node_block self.new_in_dim = ','.join(map(str, node_block.in_dim)) self.in_dim_box = CustomTextBox() self.has_edits = False # Build main_layout title_label = CustomLabel("Edit network input") title_label.setStyleSheet(style.NODE_LABEL_STYLE) title_label.setAlignment(Qt.AlignCenter) self.layout.addWidget(title_label, 0, 0, 1, 2) # Input box in_dim_label = CustomLabel("Input shape") in_dim_label.setStyleSheet(style.IN_DIM_LABEL_STYLE) in_dim_label.setAlignment(Qt.AlignRight) self.layout.addWidget(in_dim_label, 1, 0) self.in_dim_box.setText(self.new_in_dim) self.in_dim_box.setValidator(ArithmeticValidator.TENSOR) self.layout.addWidget(self.in_dim_box, 1, 1) if not node_block.is_head: self.in_dim_box.setReadOnly(True) # "Apply" button which saves changes apply_button = CustomButton("Apply") apply_button.clicked.connect(self.save_data) self.layout.addWidget(apply_button, 2, 0) # "Cancel" button which closes the dialog without saving cancel_button = CustomButton("Cancel") cancel_button.clicked.connect(self.close) self.layout.addWidget(cancel_button, 2, 1) self.layout.setColumnStretch(0, 1) self.layout.setColumnStretch(1, 1) self.render_layout()
def __init__(self, message): super().__init__("", message) # Set title label title_label = CustomLabel("Input required") title_label.setStyleSheet(style.NODE_LABEL_STYLE) title_label.setAlignment(Qt.AlignCenter) # Set message label mess_label = CustomLabel("\n" + self.content + "\n") mess_label.setAlignment(Qt.AlignCenter) # Set input reading self.input = None input_line = CustomTextBox() input_line.setValidator(QRegExpValidator(QRegExp( ArithmeticValidator.TENSOR.regExp().pattern() + "|" + ArithmeticValidator.TENSOR_LIST.regExp().pattern()))) # Add buttons to close the dialog confirm_button = CustomButton("Ok") confirm_button.clicked.connect(self.save_input) cancel_button = CustomButton("Cancel") cancel_button.clicked.connect(self.cancel) buttons = QWidget() buttons_layout = QHBoxLayout() buttons_layout.addWidget(confirm_button) buttons_layout.addWidget(cancel_button) buttons.setLayout(buttons_layout) # Compose widgets self.layout.addWidget(title_label) self.layout.addWidget(mess_label) self.layout.addWidget(input_line) self.layout.addWidget(buttons) self.render_layout()
def __init__(self, property_block: PropertyBlock): super().__init__("Edit property", "") self.property_block = property_block self.new_property = self.property_block.smt_string self.has_edits = False self.layout = QGridLayout() # Build main_layout title_label = CustomLabel("SMT property") title_label.setStyleSheet(style.NODE_LABEL_STYLE) title_label.setAlignment(Qt.AlignCenter) self.layout.addWidget(title_label, 0, 0, 1, 2) # Input box smt_label = CustomLabel("SMT-LIB definition") smt_label.setStyleSheet(style.IN_DIM_LABEL_STYLE) smt_label.setAlignment(Qt.AlignRight) self.layout.addWidget(smt_label, 1, 0) self.smt_box = CustomTextArea() self.smt_box.insertPlainText(self.new_property) self.layout.addWidget(self.smt_box, 1, 1) # "Apply" button which saves changes apply_button = CustomButton("Apply") apply_button.clicked.connect(self.save_data) self.layout.addWidget(apply_button, 2, 0) # "Cancel" button which closes the dialog without saving cancel_button = CustomButton("Cancel") cancel_button.clicked.connect(self.close) self.layout.addWidget(cancel_button, 2, 1) self.layout.setColumnStretch(0, 1) self.layout.setColumnStretch(1, 1) self.render_layout()
def __init__(self): super().__init__('Dataset transform - composition', '') # List to return self.trList = [] # 2-level parameters of the transforms self.params_2level = {} # Widgets self.available = CustomListBox() self.selected = CustomListBox() self.add_btn = CustomButton('>') self.rm_btn = CustomButton('<') self.add_btn.clicked.connect(self.add_transform) self.rm_btn.clicked.connect(self.rm_transform) # Init data self.init_layout() # Buttons self.ok_btn.clicked.connect(self.ok) self.cancel_btn.clicked.connect(self.trList.clear) self.render_layout()
class DropDownLabel(QWidget): """ This widget displays a generic parameter name and value. It features a drop-down arrow button that shows or hides the description. Attributes ---------- layout : QVBoxLayout Vertical main_layout of the widget. top : QWidget First part of the widget with name, type and default value of the parameter. top_layout : QHBoxLayout Horizontal main_layout of the top of the widget. name_label : CustomLabel Id and type of the object. type_label : CustomLabel Object type. default_label : CustomLabel Eventual default value. down_button : CustomButton Arrow button to show/hide the description of the parameter. description : CustomLabel Description of the parameter. Methods ---------- change_description_mode() This method shows or hides the description of the parameter. """ def __init__(self, name: str, parameters: dict): super().__init__() self.layout = QVBoxLayout() self.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) self.setStyleSheet(style.DROPDOWN_STYLE) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) # Top bar with short info self.top = QWidget() self.top.setContentsMargins(0, 0, 0, 0) self.top.setStyleSheet(style.DROPDOWN_TOP_STYLE) self.top_layout = QHBoxLayout() self.top_layout.setContentsMargins(0, 0, 0, 0) self.top.setLayout(self.top_layout) self.name_label = CustomLabel(name) self.name_label.setAlignment(Qt.AlignLeft) self.name_label.setStyleSheet(style.DROPDOWN_NAME_STYLE) self.top_layout.addWidget(self.name_label, Qt.AlignLeft) self.type_label = CustomLabel(parameters["type"]) self.type_label.setAlignment(Qt.AlignLeft) self.type_label.setToolTip("Type") self.type_label.setStyleSheet(style.DROPDOWN_TYPE_STYLE) self.top_layout.addWidget(self.type_label, Qt.AlignLeft) if "default" in parameters: self.default_label = CustomLabel(parameters["default"]) self.default_label.setStyleSheet(style.DROPDOWN_DEFAULT_STYLE) self.default_label.setToolTip("Default value") self.default_label.setAlignment(Qt.AlignCenter) self.top_layout.addWidget(self.default_label, Qt.AlignRight) self.down_button = CustomButton("\u25bc") self.down_button.setStyleSheet(style.DROPDOWN_ARROW_STYLE) self.down_button.clicked.connect(lambda: self.__toggle_visibility()) self.top_layout.addWidget(self.down_button, Qt.AlignRight) self.layout.addWidget(self.top) self.description = CustomLabel(parameters["description"]) self.description.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) self.description.setWordWrap(True) self.description.setStyleSheet(style.DESCRIPTION_STYLE) self.description.hide() self.layout.addWidget(self.description) def __toggle_visibility(self): """ This method toggles the visibility of the parameter description changing the arrow icon of the button. """ if self.description.isHidden(): self.description.show() self.down_button.setText("\u25b2") else: self.description.hide() self.down_button.setText("\u25bc")
class VerificationWindow(NeVerWindow): """ This class is a Window for the verification of the network. It features a combo box for choosing the verification heuristic. """ def __init__(self, nn: NeuralNetwork, properties: dict): super().__init__("Verify network") self.nn = nn self.properties = properties self.strategy = None self.params = utility.read_json(ROOT_DIR + '/res/json/verification.json') def activation_cb(methodology: str): return lambda: self.update_methodology(self.widgets[ "Verification methodology"].currentText()) body_layout = self.create_widget_layout(self.params, cb_f=activation_cb) self.layout.addLayout(body_layout) # Buttons btn_layout = QHBoxLayout() self.verify_btn = CustomButton("Verify network") self.verify_btn.clicked.connect(self.verify_network) self.cancel_btn = CustomButton("Cancel") self.cancel_btn.clicked.connect(self.close) btn_layout.addWidget(self.verify_btn) btn_layout.addWidget(self.cancel_btn) self.layout.addLayout(btn_layout) self.render_layout() def update_methodology(self, methodology: str) -> None: if methodology == 'Complete': self.strategy = verification.NeverVerification( heuristic="best_n_neurons", params=[10000]) elif methodology == 'Over-approximated': self.strategy = verification.NeverVerification( heuristic="best_n_neurons", params=[0]) else: dialog = MixedVerificationDialog() dialog.exec() self.strategy = verification.NeverVerification( heuristic="best_n_neurons", params=[dialog.n_neurons]) def verify_network(self): """ This class is a Window for the training of the network. It features a file picker for choosing the dataset and a grid of parameters for tuning the procedure. """ if self.strategy is None: err_dialog = MessageDialog("No verification methodology selected.", MessageType.ERROR) err_dialog.exec() return # Save properties path = 'never2/' + self.__repr__().split(' ')[-1].replace('>', '') + '.smt2' utility.write_smt_property(path, self.properties, 'Real') input_name = list(self.properties.keys())[0] output_name = list(self.properties.keys())[-1] # Add logger text box log_textbox = LoggerTextBox(self) logger = logging.getLogger("pynever.strategies.verification") logger.addHandler(log_textbox) logger.setLevel(logging.INFO) self.layout.addWidget(log_textbox.widget) logger.info("***** NeVer 2 - VERIFICATION *****") # Load NeVerProperty from file parser = reading.SmtPropertyParser(verification.SMTLIBProperty(path), input_name, output_name) to_verify = parser.parse_property() # Property read, delete file os.remove(path) # Launch verification self.strategy.verify(self.nn, to_verify) self.verify_btn.setEnabled(False) self.cancel_btn.setText("Close")
def __init__(self, nn: NeuralNetwork): super().__init__("Train Network") # Training elements self.nn = nn self.is_nn_trained = False self.dataset_path = "" self.dataset_params = dict() self.dataset_transform = tr.Compose([]) self.params = utility.read_json(ROOT_DIR + '/res/json/training.json') self.gui_params = dict() self.loss_f = '' self.metric = '' self.grid_layout = QGridLayout() # Dataset dt_label = CustomLabel("Dataset") dt_label.setAlignment(Qt.AlignCenter) dt_label.setStyleSheet(style.NODE_LABEL_STYLE) self.layout.addWidget(dt_label) dataset_layout = QHBoxLayout() self.widgets["dataset"] = CustomComboBox() self.widgets["dataset"].addItems( ["MNIST", "Fashion MNIST", "Custom data source..."]) self.widgets["dataset"].setCurrentIndex(-1) self.widgets["dataset"].activated \ .connect(lambda: self.setup_dataset(self.widgets["dataset"].currentText())) dataset_layout.addWidget(CustomLabel("Dataset")) dataset_layout.addWidget(self.widgets["dataset"]) self.layout.addLayout(dataset_layout) transform_layout = QHBoxLayout() self.widgets["transform"] = CustomComboBox() self.widgets["transform"].addItems([ "No transform", "Convolutional MNIST", "Fully Connected MNIST", "Custom..." ]) self.widgets["transform"].activated \ .connect(lambda: self.setup_transform(self.widgets["transform"].currentText())) transform_layout.addWidget(CustomLabel("Dataset transform")) transform_layout.addWidget(self.widgets["transform"]) self.layout.addLayout(transform_layout) # Separator sep_label = CustomLabel("Training parameters") sep_label.setAlignment(Qt.AlignCenter) sep_label.setStyleSheet(style.NODE_LABEL_STYLE) self.layout.addWidget(sep_label) # Main body # Activation functions for dynamic widgets def activation_combo(key: str): return lambda: self.update_grid_view( f"{key}:{self.widgets[key].currentText()}") def activation_line(key: str): return lambda: self.update_dict_value(key, "", self.widgets[key]. text()) body_layout = self.create_widget_layout(self.params, activation_combo, activation_line) body_layout.addLayout(self.grid_layout) self.grid_layout.setAlignment(Qt.AlignTop) self.layout.addLayout(body_layout) # Buttons btn_layout = QHBoxLayout() self.train_btn = CustomButton("Train network") self.train_btn.clicked.connect(self.train_network) self.cancel_btn = CustomButton("Cancel") self.cancel_btn.clicked.connect(self.close) btn_layout.addWidget(self.train_btn) btn_layout.addWidget(self.cancel_btn) self.layout.addLayout(btn_layout) self.render_layout()
class TrainingWindow(NeVerWindow): """ This class is a Window for the training of the network. It features a file picker for choosing the dataset and a grid of parameters for tuning the procedure. Attributes ---------- nn : NeuralNetwork The current network used in the main window, to be trained with the parameters selected here. is_nn_trained : bool Flag signaling whether the training procedure succeeded or not. dataset_path : str The dataset path to train the network. dataset_params : dict Additional parameters for generic datasets. dataset_transform : Transform Transform on the dataset. gui_params : dict The dictionary of secondary parameters displayed based on the selection. grid_layout : QGridLayout The layout to display the GUI parameters on. Methods ---------- clear_grid() Procedure to clear the grid layout. update_grid_view(str) Procedure to update the grid layout. show_layout(str) Procedure to display the grid layout. update_dict_value(str, str, str) Procedure to update the parameters. """ def __init__(self, nn: NeuralNetwork): super().__init__("Train Network") # Training elements self.nn = nn self.is_nn_trained = False self.dataset_path = "" self.dataset_params = dict() self.dataset_transform = tr.Compose([]) self.params = utility.read_json(ROOT_DIR + '/res/json/training.json') self.gui_params = dict() self.loss_f = '' self.metric = '' self.grid_layout = QGridLayout() # Dataset dt_label = CustomLabel("Dataset") dt_label.setAlignment(Qt.AlignCenter) dt_label.setStyleSheet(style.NODE_LABEL_STYLE) self.layout.addWidget(dt_label) dataset_layout = QHBoxLayout() self.widgets["dataset"] = CustomComboBox() self.widgets["dataset"].addItems( ["MNIST", "Fashion MNIST", "Custom data source..."]) self.widgets["dataset"].setCurrentIndex(-1) self.widgets["dataset"].activated \ .connect(lambda: self.setup_dataset(self.widgets["dataset"].currentText())) dataset_layout.addWidget(CustomLabel("Dataset")) dataset_layout.addWidget(self.widgets["dataset"]) self.layout.addLayout(dataset_layout) transform_layout = QHBoxLayout() self.widgets["transform"] = CustomComboBox() self.widgets["transform"].addItems([ "No transform", "Convolutional MNIST", "Fully Connected MNIST", "Custom..." ]) self.widgets["transform"].activated \ .connect(lambda: self.setup_transform(self.widgets["transform"].currentText())) transform_layout.addWidget(CustomLabel("Dataset transform")) transform_layout.addWidget(self.widgets["transform"]) self.layout.addLayout(transform_layout) # Separator sep_label = CustomLabel("Training parameters") sep_label.setAlignment(Qt.AlignCenter) sep_label.setStyleSheet(style.NODE_LABEL_STYLE) self.layout.addWidget(sep_label) # Main body # Activation functions for dynamic widgets def activation_combo(key: str): return lambda: self.update_grid_view( f"{key}:{self.widgets[key].currentText()}") def activation_line(key: str): return lambda: self.update_dict_value(key, "", self.widgets[key]. text()) body_layout = self.create_widget_layout(self.params, activation_combo, activation_line) body_layout.addLayout(self.grid_layout) self.grid_layout.setAlignment(Qt.AlignTop) self.layout.addLayout(body_layout) # Buttons btn_layout = QHBoxLayout() self.train_btn = CustomButton("Train network") self.train_btn.clicked.connect(self.train_network) self.cancel_btn = CustomButton("Cancel") self.cancel_btn.clicked.connect(self.close) btn_layout.addWidget(self.train_btn) btn_layout.addWidget(self.cancel_btn) self.layout.addLayout(btn_layout) self.render_layout() def clear_grid(self) -> None: """ This method clears the grid view of the layout, in order to display fresh new infos. """ for i in reversed(range(self.grid_layout.count())): self.grid_layout.itemAt(i).widget().deleteLater() def update_grid_view(self, caller: str) -> None: """ This method updates the grid view of the layout, displaying the corresponding parameters to the selected parameter. Parameters ---------- caller : str The parameter selected in the combo box. """ self.clear_grid() if 'Loss Function' in caller: self.loss_f = caller elif 'Precision Metric' in caller: self.metric = caller for first_level in self.params.keys(): if type(self.params[first_level]) == dict: for second_level in self.params[first_level].keys(): if caller == f"{first_level}:{second_level}" and caller not in self.gui_params: self.gui_params[caller] = self.params[first_level][ second_level] self.show_layout(caller) def show_layout(self, name: str) -> None: """ This method displays a grid layout initialized by the dictionary of parameters and default values. Parameters ---------- name : str The name of the main parameter to which the dictionary is related. """ title = CustomLabel(name.replace(':', ': ')) title.setAlignment(Qt.AlignCenter) self.grid_layout.addWidget(title, 0, 0, 1, 2) widgets_2level = dict() count = 1 for k, v in self.gui_params[name].items(): # Activation functions for dynamic widgets def activation_combo(super_key: str, key: str): return lambda: self.update_dict_value( name, key, widgets_2level[f"{super_key}:{key}"][1]. currentText()) def activation_line(super_key: str, key: str): return lambda: self.update_dict_value( name, key, widgets_2level[f"{super_key}:{key}"][1].text()) w_label = CustomLabel(k) w_label.setToolTip(v.get("description")) if v["type"] == "bool": cb = CustomComboBox() cb.addItems([str(v["value"]), str(not v["value"])]) widgets_2level[f"{name}:{k}"] = (w_label, cb) widgets_2level[f"{name}:{k}"][1].activated.connect( activation_combo(name, k)) elif "allowed" in v.keys(): cb = CustomComboBox() cb.addItems(v["allowed"]) widgets_2level[f"{name}:{k}"] = (w_label, cb) widgets_2level[f"{name}:{k}"][1].activated.connect( activation_combo(name, k)) else: widgets_2level[f"{name}:{k}"] = (w_label, CustomTextBox(str( v["value"]))) widgets_2level[f"{name}:{k}"][1].textChanged.connect( activation_line(name, k)) if v["type"] == "int": widgets_2level[f"{name}:{k}"][1].setValidator( ArithmeticValidator.INT) elif v["type"] == "float": widgets_2level[f"{name}:{k}"][1].setValidator( ArithmeticValidator.FLOAT) elif v["type"] == "tensor" or \ v["type"] == "tuple": widgets_2level[f"{name}:{k}"][1].setValidator( ArithmeticValidator.TENSOR) self.grid_layout.addWidget(widgets_2level[f"{name}:{k}"][0], count, 0) self.grid_layout.addWidget(widgets_2level[f"{name}:{k}"][1], count, 1) count += 1 def update_dict_value(self, name: str, key: str, value: str) -> None: """ This method updates the correct parameter based on the selection in the GUI. It provides the details to access the parameter and the new value to register. Parameters ---------- name : str The learning parameter name, which is the key of the main dict. key : str The name of the parameter detail, which is the key of the second-level dict. value : str The new value for parameter[name][key]. """ # Cast type if name not in self.gui_params.keys(): gui_param = self.params[name] else: gui_param = self.gui_params[name][key] if gui_param["type"] == "bool": value = value == "True" elif gui_param["type"] == "int" and value != "": value = int(value) elif gui_param["type"] == "float" and value != "": value = float(value) elif gui_param["type"] == "tuple" and value != "": value = eval(value) # Apply changes if ":" in name: first_level, second_level = name.split(":") self.params[first_level][second_level][key]["value"] = value else: self.params[name]["value"] = value def setup_dataset(self, name: str) -> None: """ This method reacts to the selection of a dataset in the dataset combo box. Depending on the selection, the correct path is saved and any additional parameters are asked. Parameters ---------- name : str The dataset name. """ if name == "MNIST": self.dataset_path = ROOT_DIR + "/data/MNIST/" elif name == "Fashion MNIST": self.dataset_path = ROOT_DIR + "/data/fMNIST/" else: datapath = QFileDialog.getOpenFileName(None, "Select data source...", "") self.dataset_path = datapath[0] # Get additional parameters via dialog if self.dataset_path != '': dialog = GenericDatasetDialog() dialog.exec() self.dataset_params = dialog.params def setup_transform(self, sel_t: str) -> None: if sel_t == 'No transform': self.dataset_transform = tr.Compose([]) elif sel_t == 'Convolutional MNIST': self.dataset_transform = tr.Compose( [tr.ToTensor(), tr.Normalize(1, 0.5)]) elif sel_t == 'Fully Connected MNIST': self.dataset_transform = tr.Compose([ tr.ToTensor(), tr.Normalize(1, 0.5), tr.Lambda(lambda x: torch.flatten(x)) ]) else: dialog = ComposeTransformDialog() dialog.exec() self.dataset_transform = tr.Compose(dialog.trList) def load_dataset(self) -> Dataset: """ This method initializes the selected dataset object, given the path loaded before. Returns ------- Dataset The dataset object. """ if self.dataset_path == ROOT_DIR + "/data/MNIST/": return dt.TorchMNIST(self.dataset_path, True, self.dataset_transform) elif self.dataset_path == ROOT_DIR + "/data/fMNIST/": return dt.TorchFMNIST(self.dataset_path, True, self.dataset_transform) elif self.dataset_path != "": return dt.GenericFileDataset(self.dataset_path, self.dataset_params["target_idx"], self.dataset_params["data_type"], self.dataset_params["delimiter"], self.dataset_transform) def train_network(self): """ This method reads the inout from the window widgets and launches the training procedure on the selected dataset. """ err_dialog = None if self.dataset_path == "": err_dialog = MessageDialog("No dataset selected.", MessageType.ERROR) elif self.widgets["Optimizer"].currentIndex() == -1: err_dialog = MessageDialog("No optimizer selected.", MessageType.ERROR) elif self.widgets["Scheduler"].currentIndex() == -1: err_dialog = MessageDialog("No scheduler selected.", MessageType.ERROR) elif self.widgets["Loss Function"].currentIndex() == -1: err_dialog = MessageDialog("No loss function selected.", MessageType.ERROR) elif self.widgets["Precision Metric"].currentIndex() == -1: err_dialog = MessageDialog("No metrics selected.", MessageType.ERROR) elif "value" not in self.params["Epochs"].keys(): err_dialog = MessageDialog("No epochs selected.", MessageType.ERROR) elif "value" not in self.params["Validation percentage"].keys(): err_dialog = MessageDialog("No validation percentage selected.", MessageType.ERROR) elif "value" not in self.params["Training batch size"].keys(): err_dialog = MessageDialog("No training batch size selected.", MessageType.ERROR) elif "value" not in self.params["Validation batch size"].keys(): err_dialog = MessageDialog("No validation batch size selected.", MessageType.ERROR) if err_dialog is not None: err_dialog.exec() return # Load dataset data = self.load_dataset() # Add logger text box log_textbox = LoggerTextBox(self) logger = logging.getLogger("pynever.strategies.training") logger.addHandler(log_textbox) logger.setLevel(logging.INFO) self.layout.addWidget(log_textbox.widget) logger.info("***** NeVer 2 - TRAINING *****") # Create optimizer dictionary of parameters opt_params = dict() for k, v in self.gui_params["Optimizer:Adam"].items(): opt_params[v["name"]] = v["value"] # Create scheduler dictionary of parameters sched_params = dict() for k, v in self.gui_params["Scheduler:ReduceLROnPlateau"].items(): sched_params[v["name"]] = v["value"] # Init loss function if self.loss_f == "Loss Function:Cross Entropy": loss = torch.nn.CrossEntropyLoss() if self.gui_params["Loss Function:Cross Entropy"]["Weight"][ "value"] != '': loss.weight = self.gui_params["Loss Function:Cross Entropy"][ "Weight"]["value"] loss.ignore_index = self.gui_params["Loss Function:Cross Entropy"][ "Ignore index"]["value"] loss.reduction = self.gui_params["Loss Function:Cross Entropy"][ "Reduction"]["value"] else: loss = fun.mse_loss loss.reduction = self.gui_params["Loss Function:MSE Loss"][ "Reduction"]["value"] # Init metrics if self.metric == "Precision Metric:Inaccuracy": metrics = PytorchMetrics.inaccuracy else: metrics = fun.mse_loss metrics.reduction = self.gui_params["Precision Metric:MSE Loss"][ "Reduction"]["value"] # Checkpoint loading checkpoints_path = self.params["Checkpoints root"].get( "value", '') + self.nn.identifier + '.pth.tar' if not os.path.isfile(checkpoints_path): checkpoints_path = None start_epoch = 0 if checkpoints_path is not None: checkpoint = torch.load(checkpoints_path) start_epoch = checkpoint["epoch"] if self.params["Epochs"]["value"] <= start_epoch: start_epoch = -1 logger.info( "Checkpoint already reached, no further training necessary" ) if start_epoch > -1: # Init train strategy train_strategy = PytorchTraining( opt.Adam, opt_params, loss, self.params["Epochs"]["value"], self.params["Validation percentage"]["value"], self.params["Training batch size"]["value"], self.params["Validation batch size"]["value"], opt.lr_scheduler.ReduceLROnPlateau, sched_params, metrics, cuda=self.params["Cuda"]["value"], train_patience=self.params["Train patience"].get( "value", None), checkpoints_root=self.params["Checkpoints root"].get( "value", ''), verbose_rate=self.params["Verbosity level"].get("value", None)) try: self.nn = train_strategy.train(self.nn, data) self.is_nn_trained = True # Delete checkpoint if the network isn't saved if self.nn.identifier == '': os.remove('.pth.tar') except Exception as e: self.nn = None dialog = MessageDialog("Training error:\n" + str(e), MessageType.ERROR) dialog.exec() self.close() self.train_btn.setEnabled(False) self.cancel_btn.setText("Close")
def __init__(self, title: str = 'NeVer Dialog', message: str = ''): super(SingleButtonDialog, self).__init__(title, message) self.button = CustomButton('Ok') self.button.clicked.connect(self.close)
def __display_tools(self): """ This method adds to the toolbar all buttons related to available tools, displaying them in rows in order to have a flexible main_layout in every position of the toolbar. """ # Setting the label of the toolbar self.addWidget(self.toolbar_tools_label) self.toolbar_tools_label.setAlignment(Qt.AlignCenter) self.toolbar_tools_label.setStyleSheet(style.NODE_LABEL_STYLE) # Setting the first row with horizontal main_layout row_1 = QWidget() row_1_layout = QHBoxLayout() row_1_layout.setSpacing(0) row_1_layout.setContentsMargins(0, 0, 0, 0) row_1_layout.setAlignment(Qt.AlignCenter) row_1.setLayout(row_1_layout) # DrawLine mode button draw_line_button = CustomButton() draw_line_button.setIcon(QIcon(ROOT_DIR + "/res/icons/line.png")) draw_line_button.setFixedSize(40, 40) draw_line_button.setToolTip("Draw line") # Insert block button insert_block_button = CustomButton() insert_block_button.setIcon(QIcon(ROOT_DIR + "/res/icons/insert.png")) insert_block_button.setFixedSize(40, 40) insert_block_button.setToolTip("Insert block in edge") # Save in a dictionary button references and add the rows to the # toolbar row_1_layout.addWidget(draw_line_button) row_1_layout.addWidget(insert_block_button) self.f_buttons["draw_line"] = draw_line_button self.f_buttons["insert_block"] = insert_block_button self.addWidget(row_1) self.addSeparator()
def __init__(self, property_block: PropertyBlock): super().__init__("Edit property", "") self.property_block = property_block self.has_edits = False self.property_list = [] self.viewer = CustomTextArea() self.viewer.setReadOnly(True) self.viewer.setFixedHeight(100) grid = QGridLayout() # Build main_layout title_label = CustomLabel("Polyhedral property") title_label.setStyleSheet(style.NODE_LABEL_STYLE) title_label.setAlignment(Qt.AlignCenter) grid.addWidget(title_label, 0, 0, 1, 3) # Labels var_label = CustomLabel("Variable") var_label.setStyleSheet(style.IN_DIM_LABEL_STYLE) var_label.setAlignment(Qt.AlignRight) grid.addWidget(var_label, 1, 0) relop_label = CustomLabel("Operator") relop_label.setStyleSheet(style.IN_DIM_LABEL_STYLE) relop_label.setAlignment(Qt.AlignCenter) grid.addWidget(relop_label, 1, 1) value_label = CustomLabel("Value") value_label.setStyleSheet(style.IN_DIM_LABEL_STYLE) value_label.setAlignment(Qt.AlignLeft) grid.addWidget(value_label, 1, 2) self.var_cb = CustomComboBox() for v in property_block.variables: self.var_cb.addItem(v) grid.addWidget(self.var_cb, 2, 0) self.op_cb = CustomComboBox() operators = ["<=", "<", ">", ">="] for o in operators: self.op_cb.addItem(o) grid.addWidget(self.op_cb, 2, 1) self.val = CustomTextBox() self.val.setValidator(ArithmeticValidator.FLOAT) grid.addWidget(self.val, 2, 2) # "Add" button which adds the constraint add_button = CustomButton("Add") add_button.clicked.connect( lambda: self.add_entry(str(self.var_cb.currentText()), str(self.op_cb.currentText()), self.val.text())) grid.addWidget(add_button, 3, 0) # "Save" button which saves the state save_button = CustomButton("Save") save_button.clicked.connect(self.save_property) grid.addWidget(save_button, 3, 1) # "Cancel" button which closes the dialog without saving cancel_button = CustomButton("Cancel") cancel_button.clicked.connect(self.close) grid.addWidget(cancel_button, 3, 2) grid.setColumnStretch(0, 1) grid.setColumnStretch(1, 1) grid.setColumnStretch(2, 1) self.layout.addLayout(grid) self.layout.addWidget(self.viewer, 3) self.render_layout()