diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py index 933f919b..e05f9d80 100644 --- a/compiler/characterizer/__init__.py +++ b/compiler/characterizer/__init__.py @@ -19,6 +19,7 @@ from .simulation import * from .measurements import * from .model_check import * from .analytical_util import * +from .regression_model import * debug.info(1,"Initializing characterizer...") OPTS.spice_exe = "" diff --git a/compiler/characterizer/analytical_util.py b/compiler/characterizer/analytical_util.py index 79cb1294..43435667 100644 --- a/compiler/characterizer/analytical_util.py +++ b/compiler/characterizer/analytical_util.py @@ -254,9 +254,9 @@ def scale_input_datapoint(point, file_path): training. """ maxs, mins, avgs = get_max_min_from_file(file_path) - debug.info(1, "maxs={}".format(maxs)) - debug.info(1, "mins={}".format(mins)) - debug.info(1, "point={}".format(point)) + debug.info(3, "maxs={}".format(maxs)) + debug.info(3, "mins={}".format(mins)) + debug.info(3, "point={}".format(point)) scaled_point = [] for feature, mx, mn in zip(point, maxs, mins): diff --git a/compiler/characterizer/linear_regression.py b/compiler/characterizer/linear_regression.py index 5d4cbe49..fac7a170 100644 --- a/compiler/characterizer/linear_regression.py +++ b/compiler/characterizer/linear_regression.py @@ -6,131 +6,17 @@ # All rights reserved. # -from .analytical_util import * -from .simulation import simulation +from .regression_model import regression_model from globals import OPTS import debug -import os from sklearn.linear_model import LinearRegression -import math -relative_data_path = "/sim_data" -data_fnames = ["rise_delay.csv", - "fall_delay.csv", - "rise_slew.csv", - "fall_slew.csv", - "write1_power.csv", - "write0_power.csv", - "read1_power.csv", - "read0_power.csv", - "leakage_data.csv"] -# Positions must correspond to data_fname list -lib_dnames = ["delay_lh", - "delay_hl", - "slew_lh", - "slew_hl", - "write1_power", - "write0_power", - "read1_power", - "read0_power", - "leakage_power"] -data_dir = OPTS.openram_tech+relative_data_path -data_paths = {dname:data_dir +'/'+fname for dname, fname in zip(lib_dnames, data_fnames)} -class linear_regression(simulation): +class linear_regression(regression_model): def __init__(self, sram, spfile, corner): super().__init__(sram, spfile, corner) - self.set_corner(corner) - - def get_lib_values(self, slews, loads): - """ - A model and prediction is created for each output needed for the LIB - """ - - log_num_words = math.log(OPTS.num_words, 2) - debug.info(1, "OPTS.words_per_row={}".format(OPTS.words_per_row)) - model_inputs = [log_num_words, - OPTS.word_size, - OPTS.words_per_row, - self.sram.width * self.sram.height, - process_transform[self.process], - self.vdd_voltage, - self.temperature] - - self.create_measurement_names() - models = self.train_models() - - # Set delay/power for slews and loads - port_data = self.get_empty_measure_data_dict() - debug.info(1, 'Slew, Load, Delay(ns), Slew(ns)') - max_delay = 0.0 - for slew in slews: - for load in loads: - # List returned with value order being delay, power, leakage, slew - sram_vals = self.get_predictions(model_inputs+[slew, load], models) - # Delay is only calculated on a single port and replicated for now. - for port in self.all_ports: - port_data[port]['delay_lh'].append(sram_vals['delay_lh']) - port_data[port]['delay_hl'].append(sram_vals['delay_hl']) - port_data[port]['slew_lh'].append(sram_vals['slew_lh']) - port_data[port]['slew_hl'].append(sram_vals['slew_hl']) - - port_data[port]['write1_power'].append(sram_vals['write1_power']) - port_data[port]['write0_power'].append(sram_vals['write0_power']) - port_data[port]['read1_power'].append(sram_vals['read1_power']) - port_data[port]['read0_power'].append(sram_vals['read0_power']) - - # Disabled power not modeled. Copied from other power predictions - port_data[port]['disabled_write1_power'].append(sram_vals['write1_power']) - port_data[port]['disabled_write0_power'].append(sram_vals['write0_power']) - port_data[port]['disabled_read1_power'].append(sram_vals['read1_power']) - port_data[port]['disabled_read0_power'].append(sram_vals['read0_power']) - - - # Estimate the period as double the delay with margin - period_margin = 0.1 - sram_data = {"min_period": sram_vals['delay_lh'] * 2, - "leakage_power": sram_vals["leakage_power"]} - - debug.info(2, "SRAM Data:\n{}".format(sram_data)) - debug.info(2, "Port Data:\n{}".format(port_data)) - - return (sram_data, port_data) - - def get_predictions(self, model_inputs, models): - """ - Generate a model and prediction for LIB output - """ - - #Scaled the inputs using first data file as a reference - data_name = lib_dnames[0] - scaled_inputs = np.asarray([scale_input_datapoint(model_inputs, data_paths[data_name])]) - - predictions = {} - for dname in data_paths.keys(): - path = data_paths[dname] - m = models[dname] - - features, labels = get_scaled_data(path) - scaled_pred = self.model_prediction(m, scaled_inputs) - pred = unscale_data(scaled_pred.tolist(), path) - debug.info(1,"Unscaled Prediction = {}".format(pred)) - predictions[dname] = pred[0][0] - return predictions - - def train_models(self): - """ - Generate and return models - """ - models = {} - for dname, dpath in data_paths.items(): - features, labels = get_scaled_data(dpath) - model = self.generate_model(features, labels) - models[dname] = model - return models - def generate_model(self, features, labels): """ diff --git a/compiler/characterizer/neural_network.py b/compiler/characterizer/neural_network.py index 94da9a66..57db4580 100644 --- a/compiler/characterizer/neural_network.py +++ b/compiler/characterizer/neural_network.py @@ -6,121 +6,19 @@ # All rights reserved. # -from .analytical_util import * -from .simulation import simulation +from .regression_model import regression_model from globals import OPTS import debug -import os -import math -import numpy as np from tensorflow import keras from tensorflow.keras import layers import tensorflow as tf -relative_data_path = "/sim_data" -data_fnames = ["rise_delay.csv", - "fall_delay.csv", - "rise_slew.csv", - "fall_slew.csv", - "write1_power.csv", - "write0_power.csv", - "read1_power.csv", - "read0_power.csv", - "leakage_data.csv"] - -data_dir = OPTS.openram_tech+relative_data_path -data_paths = [data_dir +'/'+fname for fname in data_fnames] -class neural_network(simulation): +class neural_network(regression_model): def __init__(self, sram, spfile, corner): super().__init__(sram, spfile, corner) - self.set_corner(corner) - - def get_lib_values(self, slews, loads): - """ - A model and prediction is created for each output needed for the LIB - """ - - log_num_words = math.log(OPTS.num_words, 2) - debug.info(1, "OPTS.words_per_row={}".format(OPTS.words_per_row)) - model_inputs = [log_num_words, - OPTS.word_size, - OPTS.words_per_row, - self.sram.width * self.sram.height, - process_transform[self.process], - self.vdd_voltage, - self.temperature] - - self.create_measurement_names() - models = self.train_models() - - # Set delay/power for slews and loads - port_data = self.get_empty_measure_data_dict() - debug.info(1, 'Slew, Load, Delay(ns), Slew(ns)') - max_delay = 0.0 - for slew in slews: - for load in loads: - # List returned with value order being delay, power, leakage, slew - # FIXME: make order less hard coded - sram_vals = self.get_predictions(model_inputs+[slew, load], models) - # Delay is only calculated on a single port and replicated for now. - for port in self.all_ports: - port_data[port]['delay_lh'].append(sram_vals[0][0][0]) - port_data[port]['delay_hl'].append(sram_vals[1][0][0]) - port_data[port]['slew_lh'].append(sram_vals[2][0][0]) - port_data[port]['slew_hl'].append(sram_vals[3][0][0]) - - port_data[port]['write1_power'].append(sram_vals[4][0][0]) - port_data[port]['write0_power'].append(sram_vals[5][0][0]) - port_data[port]['read1_power'].append(sram_vals[6][0][0]) - port_data[port]['read0_power'].append(sram_vals[7][0][0]) - - # Disabled power not modeled. Copied from other power predictions - port_data[port]['disabled_write1_power'].append(sram_vals[4][0][0]) - port_data[port]['disabled_write0_power'].append(sram_vals[5][0][0]) - port_data[port]['disabled_read1_power'].append(sram_vals[6][0][0]) - port_data[port]['disabled_read0_power'].append(sram_vals[7][0][0]) - - - # Estimate the period as double the delay with margin - period_margin = 0.1 - sram_data = {"min_period": sram_vals[0][0][0] * 2, - "leakage_power": sram_vals[8][0][0]} - - debug.info(2, "SRAM Data:\n{}".format(sram_data)) - debug.info(2, "Port Data:\n{}".format(port_data)) - - return (sram_data, port_data) - - def get_predictions(self, model_inputs, models): - """ - Generate a model and prediction for LIB output - """ - - scaled_inputs = np.asarray([scale_input_datapoint(model_inputs, data_paths[0])]) - - predictions = [] - for m, path in zip(models, data_paths): - features, labels = get_scaled_data(path) - scaled_pred = self.model_prediction(m, scaled_inputs) - pred = unscale_data(scaled_pred.tolist(), path) - debug.info(1,"Unscaled Prediction = {}".format(pred)) - predictions.append(pred) - return predictions - - def train_models(self): - """ - Generate and return models - """ - models = [] - for path in data_paths: - features, labels = get_scaled_data(path) - model = self.generate_model(features, labels) - models.append(model) - return models - def generate_model(self, features, labels): """ diff --git a/compiler/characterizer/regression_model.py b/compiler/characterizer/regression_model.py new file mode 100644 index 00000000..d79d2faf --- /dev/null +++ b/compiler/characterizer/regression_model.py @@ -0,0 +1,135 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# + +from .analytical_util import * +from .simulation import simulation +from globals import OPTS +import debug + +import math + +relative_data_path = "/sim_data" +data_fnames = ["rise_delay.csv", + "fall_delay.csv", + "rise_slew.csv", + "fall_slew.csv", + "write1_power.csv", + "write0_power.csv", + "read1_power.csv", + "read0_power.csv", + "leakage_data.csv"] +# Positions must correspond to data_fname list +lib_dnames = ["delay_lh", + "delay_hl", + "slew_lh", + "slew_hl", + "write1_power", + "write0_power", + "read1_power", + "read0_power", + "leakage_power"] +data_dir = OPTS.openram_tech+relative_data_path +data_paths = {dname:data_dir +'/'+fname for dname, fname in zip(lib_dnames, data_fnames)} + +class regression_model(simulation): + + def __init__(self, sram, spfile, corner): + super().__init__(sram, spfile, corner) + self.set_corner(corner) + + def get_lib_values(self, slews, loads): + """ + A model and prediction is created for each output needed for the LIB + """ + + debug.info(1, "Characterizing SRAM using linear regression models.") + log_num_words = math.log(OPTS.num_words, 2) + model_inputs = [log_num_words, + OPTS.word_size, + OPTS.words_per_row, + self.sram.width * self.sram.height, + process_transform[self.process], + self.vdd_voltage, + self.temperature] + + self.create_measurement_names() + models = self.train_models() + + # Set delay/power for slews and loads + port_data = self.get_empty_measure_data_dict() + debug.info(1, 'Slew, Load, Port, Delay(ns), Slew(ns)') + max_delay = 0.0 + for slew in slews: + for load in loads: + # List returned with value order being delay, power, leakage, slew + sram_vals = self.get_predictions(model_inputs+[slew, load], models) + # Delay is only calculated on a single port and replicated for now. + for port in self.all_ports: + port_data[port]['delay_lh'].append(sram_vals['delay_lh']) + port_data[port]['delay_hl'].append(sram_vals['delay_hl']) + port_data[port]['slew_lh'].append(sram_vals['slew_lh']) + port_data[port]['slew_hl'].append(sram_vals['slew_hl']) + + port_data[port]['write1_power'].append(sram_vals['write1_power']) + port_data[port]['write0_power'].append(sram_vals['write0_power']) + port_data[port]['read1_power'].append(sram_vals['read1_power']) + port_data[port]['read0_power'].append(sram_vals['read0_power']) + + # Disabled power not modeled. Copied from other power predictions + port_data[port]['disabled_write1_power'].append(sram_vals['write1_power']) + port_data[port]['disabled_write0_power'].append(sram_vals['write0_power']) + port_data[port]['disabled_read1_power'].append(sram_vals['read1_power']) + port_data[port]['disabled_read0_power'].append(sram_vals['read0_power']) + + debug.info(1, '{}, {}, {}, {}, {}'.format(slew, + load, + port, + sram_vals['delay_lh'], + sram_vals['slew_lh'])) + # Estimate the period as double the delay with margin + period_margin = 0.1 + sram_data = {"min_period": sram_vals['delay_lh'] * 2, + "leakage_power": sram_vals["leakage_power"]} + + debug.info(2, "SRAM Data:\n{}".format(sram_data)) + debug.info(2, "Port Data:\n{}".format(port_data)) + + return (sram_data, port_data) + + def get_predictions(self, model_inputs, models): + """ + Generate a model and prediction for LIB output + """ + + #Scaled the inputs using first data file as a reference + data_name = lib_dnames[0] + scaled_inputs = np.asarray([scale_input_datapoint(model_inputs, data_paths[data_name])]) + + predictions = {} + for dname in data_paths.keys(): + path = data_paths[dname] + m = models[dname] + + features, labels = get_scaled_data(path) + scaled_pred = self.model_prediction(m, scaled_inputs) + pred = unscale_data(scaled_pred.tolist(), path) + debug.info(2,"Unscaled Prediction = {}".format(pred)) + predictions[dname] = pred[0][0] + return predictions + + def train_models(self): + """ + Generate and return models + """ + models = {} + for dname, dpath in data_paths.items(): + features, labels = get_scaled_data(dpath) + model = self.generate_model(features, labels) + models[dname] = model + return models + \ No newline at end of file