• 基于变分自动编码器VAE的电池剩余使用寿命RUL估计


    加载模块

    1. import math
    2. import itertools
    3. import numpy as np
    4. import pandas as pd
    5. import seaborn as sns
    6. import tensorflow as tf
    7. from keras import layers
    8. from sklearn.svm import SVR
    9. from tensorflow import keras
    10. from keras import backend as K
    11. import matplotlib.pyplot as plt
    12. from keras.regularizers import l2
    13. from keras.regularizers import l1_l2
    14. from keras.models import load_model
    15. from keras.callbacks import ReduceLROnPlateau
    16. from sklearn.model_selection import KFold, GridSearchCV
    17. from sklearn.preprocessing import StandardScaler
    18. from sklearn.pipeline import make_pipeline
    19. from sklearn.model_selection import GroupShuffleSplit
    20. from sklearn.metrics import mean_squared_error, r2_score
    21. from sklearn.model_selection import train_test_split, cross_val_score, cross_validate
    22. from keras.callbacks import Callback, EarlyStopping, ModelCheckpoint, TensorBoard, LambdaCallback
    23. from keras.layers import Input, Dense, Lambda, LSTM, RepeatVector, Bidirectional, Masking, Dropout, BatchNormalization

    读取数据

    1. # Data reading
    2. data_dir = './original_data/'
    3. # Specify the file path and column names
    4. file_path = os.path.join(data_dir, 'battery_RUL.txt')
    5. # Specify the column names
    6. column_names = [
    7. 'unit_nr',
    8. 'time_cycles',
    9. 's_discharge_t',
    10. 's_decrement_3.6-3.4V',
    11. 's_max_voltage_discharge',
    12. 's_min_voltage_charge',
    13. 'Time_at_4.15V_s',
    14. 's_time_constant_current',
    15. 's_charging_time',
    16. 'RUL'
    17. ]
    18. # Read the text file into a DataFrame
    19. df = pd.read_csv(file_path, sep='\s+', header=None, skiprows=0, names=column_names)
    20. # Calculate the unique number of batteries
    21. unique_batteries = df['unit_nr'].nunique()
    22. print("\n Unique number of batteries:", unique_batteries)
    23. # Check for missing values
    24. if df.isnull().any().any():
    25. print("\n There are missing values in the DataFrame.")
    26. # Print the shape of the DataFrame
    27. print("\n DataFrame shape:", df.shape)
    28. # print df info
    29. print(df.info())
    30. # Print the first few rows of the DataFrame
    31. print("\n First few rows of the DataFrame:")
    32. df.head()

    Unique number of batteries: 14

    DataFrame shape: (15064, 10)

    RangeIndex: 15064 entries, 0 to 15063
    Data columns (total 10 columns):
    # Column Non-Null Count Dtype
    --- ------ -------------- -----
    0 unit_nr 15064 non-null float64
    1 time_cycles 15064 non-null float64
    2 s_discharge_t 15064 non-null float64
    3 s_decrement_3.6-3.4V 15064 non-null float64
    4 s_max_voltage_discharge 15064 non-null float64
    5 s_min_voltage_charge 15064 non-null float64
    6 Time_at_4.15V_s 15064 non-null float64
    7 s_time_constant_current 15064 non-null float64
    8 s_charging_time 15064 non-null float64
    9 RUL 15064 non-null int64
    dtypes: float64(9), int64(1)
    memory usage: 1.1 MB
    None

    First few rows of the DataFrame:

    图片

    数据前处理

    1. # Filter rows where 'time_cycles' is equal to 1
    2. df_at_cycle_1 = df[df['time_cycles'] == 1]
    3. # Create a bar chart with all battery units on the X-axis
    4. plt.figure(figsize=(12, 6))
    5. plt.bar(df_at_cycle_1['unit_nr'], df_at_cycle_1['RUL'])
    6. plt.xlabel('Battery Number')
    7. plt.ylabel('RUL at Cycle 1')
    8. plt.title('RUL Values at the Beginning of Cycle 1 for Each Battery Unit')
    9. plt.xticks(df_at_cycle_1['unit_nr']) # Set X-axis ticks explicitly
    10. plt.tight_layout()
    11. plt.show()

    图片

    1. plt.figure(figsize = (8,8))
    2. sns.heatmap(df.corr(),annot=True, cbar=False, cmap='Blues', fmt='.1f')

    图片

    Correlation between RUL and:

    Max. Voltage Dischar. (V) is 0.8

    Min. Voltage Charg. (V) is -0.8

    Time at 4.15V (s) is 0.2

    Cycle index is -1.0

    Discharge Time (s), Decrement 3.6-3.4V (s), Time constant current (s) and Charging time (s) are 0.

    And correlation between Time at 4.15V and these four features are 0.8, 0.5,0.6 and 0.7.

    1. df1=df.drop(['s_discharge_t', 's_decrement_3.6-3.4V', 's_time_constant_current','s_charging_time'], axis=1)
    2. plt.figure(figsize = (4,4))
    3. sns.heatmap(df1.corr(),annot=True, cbar=False, cmap='Blues', fmt='.1f')

    图片

    df1.head()

    图片

    1. def exponential_smoothing(df, sensors, n_samples, alpha=0.4):
    2. df = df.copy()
    3. # first, take the exponential weighted mean
    4. df[sensors] = df.groupby('unit_nr', group_keys=True)[sensors].apply(lambda x: x.ewm(alpha=alpha).mean()).reset_index(level=0, drop=True)
    5. # second, drop first n_samples of each unit_nr to reduce filter delay
    6. def create_mask(data, samples):
    7. result = np.ones_like(data)
    8. result[0:samples] = 0
    9. return result
    10. mask = df.groupby('unit_nr')['unit_nr'].transform(create_mask, samples=n_samples).astype(bool)
    11. df = df[mask]
    12. return df
    13. #-----------------------------------------------------------------------------------------------------------------------
    14. def data_standardization(df, sensors):
    15. df = df.copy()
    16. # Apply StandardScaler to the sensor data
    17. scaler = StandardScaler()
    18. df[sensors] = scaler.fit_transform(df[sensors])
    19. return df
    20. # MMS_X = MinMaxScaler()
    21. # mms_y = MinMaxScaler()
    22. #-----------------------------------------------------------------------------------------------------------------------
    23. def gen_train_data(df, sequence_length, columns):
    24. data = df[columns].values
    25. num_elements = data.shape[0]
    26. # -1 and +1 because of Python indexing
    27. for start, stop in zip(range(0, num_elements-(sequence_length-1)), range(sequence_length, num_elements+1)):
    28. yield data[start:stop, :]
    29. #-----------------------------------------------------------------------------------------------------------------------
    30. def gen_data_wrapper(df, sequence_length, columns, unit_nrs=np.array([])):
    31. if unit_nrs.size <= 0:
    32. unit_nrs = df['unit_nr'].unique()
    33. data_gen = (list(gen_train_data(df[df['unit_nr']==unit_nr], sequence_length, columns))
    34. for unit_nr in unit_nrs)
    35. data_array = np.concatenate(list(data_gen)).astype(np.float32)
    36. return data_array
    37. #-----------------------------------------------------------------------------------------------------------------------
    38. def gen_labels(df, sequence_length, label):
    39. data_matrix = df[label].values
    40. num_elements = data_matrix.shape[0]
    41. # -1 because I want to predict the rul of that last row in the sequence, not the next row
    42. return data_matrix[sequence_length-1:num_elements, :]
    43. #-----------------------------------------------------------------------------------------------------------------------
    44. def gen_label_wrapper(df, sequence_length, label, unit_nrs=np.array([])):
    45. if unit_nrs.size <= 0:
    46. unit_nrs = df['unit_nr'].unique()
    47. label_gen = [gen_labels(df[df['unit_nr']==unit_nr], sequence_length, label)
    48. for unit_nr in unit_nrs]
    49. label_array = np.concatenate(label_gen).astype(np.float32)
    50. return label_array
    51. #---------Original code------------------------------------------------------------------------------------------------------
    52. def gen_test_data(df, sequence_length, columns, mask_value):
    53. if df.shape[0] < sequence_length:
    54. data_matrix = np.full(shape=(sequence_length, len(columns)), fill_value=mask_value) # pad
    55. idx = data_matrix.shape[0] - df.shape[0]
    56. data_matrix[idx:,:] = df[columns].values # fill with available data
    57. else:
    58. data_matrix = df[columns].values
    59. # specifically yield the last possible sequence
    60. stop = data_matrix.shape[0]
    61. start = stop - sequence_length
    62. for i in list(range(1)):
    63. yield data_matrix[start:stop, :]
    64. #---------------------------------------------------------------------------------------------------------------------------
    65. def change_test_index(df, initial_unit_number, start_index, end_index, min_rows, max_rows):
    66. df.reset_index(drop=True, inplace=True)
    67. y_test = [] # Initialize an empty list to store y_test values
    68. y_test.append(df.loc[0, 'RUL'])
    69. while end_index < len(df):
    70. # Calculate the number of rows to be assigned to the current unit_nr
    71. num_rows = min_rows + (end_index % (max_rows - min_rows + 1))
    72. end_index = end_index + num_rows
    73. # Update the unit_nr for the current block of rows
    74. df.loc[start_index:end_index, 'unit_nr'] = initial_unit_number
    75. # Update the "time_cycles" column starting from the first row with "time_cycles" == 1
    76. time_cycle_to_change = end_index + 1
    77. df.loc[time_cycle_to_change, 'time_cycles'] = 1
    78. # Append the values to y_test (replace 'column_name' with the actual column name you want to append)
    79. y_test.append(df.loc[time_cycle_to_change, 'RUL'])
    80. # Update the starting and ending index for the next block of rows
    81. start_index = end_index + 1
    82. initial_unit_number += 1
    83. # Drop rows with NaN values at the end of DataFrame 'df'
    84. df.dropna(axis=0, how='any', inplace=True)
    85. # Drop any NaN values at the end of list 'y_test'
    86. while len(y_test) > 0 and pd.isnull(y_test[-1]):
    87. y_test.pop()
    88. return df, y_test

    获取数据

    1. def get_data(df, sensors, sequence_length, alpha):
    2. # List of battery units
    3. battery_units = range(1, 15)
    4. sensor_names = ['s_{}'.format(i+1) for i in range(0,10)]
    5. # Define the number of batteries for training and testing
    6. train_batteries = 12
    7. test_batteries = 2
    8. # Extract the batteries for training and testing
    9. train_units = battery_units[:train_batteries]
    10. test_units = battery_units[train_batteries:train_batteries + test_batteries]
    11. # Create the training and testing datasets
    12. train = df[df['unit_nr'].isin(train_units)].copy() # Use copy to avoid the SettingWithCopyWarning
    13. test = df[df['unit_nr'].isin(test_units)].copy() # Use copy to avoid the SettingWithCopyWarning
    14. X_test_pre, y_test = change_test_index(test, 13, 0, 0, 230, 240)
    15. # y_test = pd.Series(y_test) # Convert y_test list to a pandas Series
    16. # remove unused sensors
    17. drop_sensors = [element for element in sensor_names if element not in sensors]
    18. # Apply standardization to the training and testing data using data_standardization function
    19. standard_train = data_standardization(train, sensors)
    20. standard_test = data_standardization(test, sensors)
    21. # Exponential smoothing of training and testing data
    22. X_train_pre = exponential_smoothing(standard_train, sensors, 0, alpha)
    23. X_test_pre = exponential_smoothing(standard_test, sensors, 0, alpha)
    24. # Train-validation split
    25. gss = GroupShuffleSplit(n_splits=1, train_size=0.85, random_state=42)
    26. # Generate the train/val for each sample by iterating over the train and val units
    27. for train_unit, val_unit in gss.split(X_train_pre['unit_nr'].unique(), groups=X_train_pre['unit_nr'].unique()):
    28. train_unit = X_train_pre['unit_nr'].unique()[train_unit] # gss returns indexes and index starts at 1
    29. val_unit = X_train_pre['unit_nr'].unique()[val_unit]
    30. x_train = gen_data_wrapper(X_train_pre, sequence_length, sensors, train_unit)
    31. y_train = gen_label_wrapper(X_train_pre, sequence_length, ['RUL'], train_unit)
    32. x_val = gen_data_wrapper(X_train_pre, sequence_length, sensors, val_unit)
    33. y_val = gen_label_wrapper(X_train_pre, sequence_length, ['RUL'], val_unit)
    34. # create sequences for test
    35. test_gen = (list(gen_test_data(X_test_pre[X_test_pre['unit_nr']==unit_nr], sequence_length, sensors, -99.))
    36. for unit_nr in X_test_pre['unit_nr'].unique())
    37. x_test = np.concatenate(list(test_gen)).astype(np.float32)
    38. return x_train, y_train, x_val, y_val, x_test, y_test

    训练回调

    1. # --------------------------------------- TRAINING CALLBACKS ---------------------------------------
    2. class save_latent_space_viz(Callback):
    3. def __init__(self, model, data, target):
    4. self.model = model
    5. self.data = data
    6. self.target = target
    7. def on_train_begin(self, logs={}):
    8. self.best_val_loss = 100000
    9. def on_epoch_end(self, epoch, logs=None):
    10. encoder = self.model.layers[0]
    11. if logs.get('val_loss') < self.best_val_loss:
    12. self.best_val_loss = logs.get('val_loss')
    13. viz_latent_space(encoder, self.data, self.target, epoch, True, False)
    14. def get_callbacks(model, data, target):
    15. model_callbacks = [
    16. EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=30),
    17. ModelCheckpoint(filepath='./checkpoints/checkpoint',monitor='val_loss', mode='min', verbose=1, save_best_only=True, save_weights_only=True),
    18. TensorBoard(log_dir='./logs'),
    19. save_latent_space_viz(model, data, target)
    20. ]
    21. return model_callbacks
    22. def viz_latent_space(encoder, data, targets=[], epoch='Final', save=False, show=True):
    23. z, _, _ = encoder.predict(data)
    24. plt.figure(figsize=(3, 3)) # Smaller figsize value to reduce the plot size
    25. if len(targets) > 0:
    26. plt.scatter(z[:, 1], z[:, 0], c=targets)
    27. else:
    28. plt.scatter(z[:, 1], z[:, 0])
    29. plt.xlabel('z - dim 1')
    30. plt.ylabel('z - dim 2')
    31. plt.colorbar()
    32. if show:
    33. plt.show()
    34. if save:
    35. plt.savefig('./images/latent_space_epoch' + str(epoch) + '.png')
    36. return z

    最佳学习率

    1. # ----------------------------------------- FIND OPTIMAL LR ----------------------------------------
    2. class LRFinder:
    3. """
    4. Cyclical LR, code tailored from:
    5. https://towardsdatascience.com/estimating-optimal-learning-rate-for-a-deep-neural-network-ce32f2556ce0
    6. """
    7. def __init__(self, model):
    8. self.model = model
    9. self.losses = []
    10. self.lrs = []
    11. self.best_loss = 1e9
    12. def on_batch_end(self, batch, logs):
    13. # Log the learning rate
    14. lr = K.get_value(self.model.optimizer.lr)
    15. self.lrs.append(lr)
    16. # Log the loss
    17. loss = logs['loss']
    18. self.losses.append(loss)
    19. # Check whether the loss got too large or NaN
    20. if batch > 5 and (math.isnan(loss) or loss > self.best_loss * 4):
    21. self.model.stop_training = True
    22. return
    23. if loss < self.best_loss:
    24. self.best_loss = loss
    25. # Increase the learning rate for the next batch
    26. lr *= self.lr_mult
    27. K.set_value(self.model.optimizer.lr, lr)
    28. def find(self, x_train, y_train, start_lr, end_lr, batch_size=64, epochs=1, **kw_fit):
    29. # If x_train contains data for multiple inputs, use length of the first input.
    30. # Assumption: the first element in the list is single input; NOT a list of inputs.
    31. N = x_train[0].shape[0] if isinstance(x_train, list) else x_train.shape[0]
    32. # Compute number of batches and LR multiplier
    33. num_batches = epochs * N / batch_size
    34. self.lr_mult = (float(end_lr) / float(start_lr)) ** (float(1) / float(num_batches))
    35. # Save weights into a file
    36. initial_weights = self.model.get_weights()
    37. # Remember the original learning rate
    38. original_lr = K.get_value(self.model.optimizer.lr)
    39. # Set the initial learning rate
    40. K.set_value(self.model.optimizer.lr, start_lr)
    41. callback = LambdaCallback(on_batch_end=lambda batch, logs: self.on_batch_end(batch, logs))
    42. self.model.fit(x_train, y_train,
    43. batch_size=batch_size, epochs=epochs,
    44. callbacks=[callback],
    45. **kw_fit)
    46. # Restore the weights to the state before model fitting
    47. self.model.set_weights(initial_weights)
    48. # Restore the original learning rate
    49. K.set_value(self.model.optimizer.lr, original_lr)
    50. def find_generator(self, generator, start_lr, end_lr, epochs=1, steps_per_epoch=None, **kw_fit):
    51. if steps_per_epoch is None:
    52. try:
    53. steps_per_epoch = len(generator)
    54. except (ValueError, NotImplementedError) as e:
    55. raise e('`steps_per_epoch=None` is only valid for a'
    56. ' generator based on the '
    57. '`keras.utils.Sequence`'
    58. ' class. Please specify `steps_per_epoch` '
    59. 'or use the `keras.utils.Sequence` class.')
    60. self.lr_mult = (float(end_lr) / float(start_lr)) ** (float(1) / float(epochs * steps_per_epoch))
    61. # Save weights into a file
    62. initial_weights = self.model.get_weights()
    63. # Remember the original learning rate
    64. original_lr = K.get_value(self.model.optimizer.lr)
    65. # Set the initial learning rate
    66. K.set_value(self.model.optimizer.lr, start_lr)
    67. callback = LambdaCallback(on_batch_end=lambda batch,
    68. logs: self.on_batch_end(batch, logs))
    69. self.model.fit_generator(generator=generator,
    70. epochs=epochs,
    71. steps_per_epoch=steps_per_epoch,
    72. callbacks=[callback],
    73. **kw_fit)
    74. # Restore the weights to the state before model fitting
    75. self.model.set_weights(initial_weights)
    76. # Restore the original learning rate
    77. K.set_value(self.model.optimizer.lr, original_lr)
    78. def plot_loss(self, n_skip_beginning=10, n_skip_end=5, x_scale='log'):
    79. """
    80. Plots the loss.
    81. Parameters:
    82. n_skip_beginning - number of batches to skip on the left.
    83. n_skip_end - number of batches to skip on the right.
    84. """
    85. plt.ylabel("loss")
    86. plt.xlabel("learning rate (log scale)")
    87. plt.plot(self.lrs[n_skip_beginning:-n_skip_end], self.losses[n_skip_beginning:-n_skip_end])
    88. plt.xscale(x_scale)
    89. plt.show()
    90. def plot_loss_change(self, sma=1, n_skip_beginning=10, n_skip_end=5, y_lim=(-0.01, 0.01)):
    91. """
    92. Plots rate of change of the loss function.
    93. Parameters:
    94. sma - number of batches for simple moving average to smooth out the curve.
    95. n_skip_beginning - number of batches to skip on the left.
    96. n_skip_end - number of batches to skip on the right.
    97. y_lim - limits for the y axis.
    98. """
    99. derivatives = self.get_derivatives(sma)[n_skip_beginning:-n_skip_end]
    100. lrs = self.lrs[n_skip_beginning:-n_skip_end]
    101. plt.ylabel("rate of loss change")
    102. plt.xlabel("learning rate (log scale)")
    103. plt.plot(lrs, derivatives)
    104. plt.xscale('log')
    105. plt.ylim(y_lim)
    106. plt.show()
    107. def get_derivatives(self, sma):
    108. assert sma >= 1
    109. derivatives = [0] * sma
    110. for i in range(sma, len(self.lrs)):
    111. derivatives.append((self.losses[i] - self.losses[i - sma]) / sma)
    112. return derivatives
    113. def get_best_lr(self, sma, n_skip_beginning=10, n_skip_end=5):
    114. derivatives = self.get_derivatives(sma)
    115. best_der_idx = np.argmin(derivatives[n_skip_beginning:-n_skip_end])
    116. return self.lrs[n_skip_beginning:-n_skip_end][best_der_idx]

    结果

    1. # --------------------------------------------- RESULTS --------------------------------------------
    2. def get_model(path):
    3. saved_VRAE_model = load_model(path, compile=False)
    4. # return encoder, regressor
    5. return saved_VRAE_model.layers[1], saved_VRAE_model.layers[2]
    6. def evaluate(y_true, y_hat, label='test'):
    7. mse = mean_squared_error(y_true, y_hat)
    8. rmse = np.sqrt(mse)
    9. variance = r2_score(y_true, y_hat)
    10. print('{} set RMSE:{}, R2:{}'.format(label, rmse, variance))
    11. return rmse, variance
    12. def score(y_true, y_hat):
    13. res = 0
    14. for true, hat in zip(y_true, y_hat):
    15. subs = hat - true
    16. if subs < 0:
    17. res = res + np.exp(-subs/10)[0]-1
    18. else:
    19. res = res + np.exp(subs/13)[0]-1
    20. print("score: ", res)
    21. def results(path, x_train, y_train, x_test, y_test):
    22. # Get model
    23. encoder, regressor = get_model(path)
    24. # Latent space
    25. train_mu = viz_latent_space(encoder, x_train, y_train)
    26. test_mu = viz_latent_space(encoder, x_test, y_test)
    27. # Evaluate
    28. y_hat_train = regressor.predict(train_mu)
    29. y_hat_test = regressor.predict(test_mu)
    30. evaluate(y_train, y_hat_train, 'train')
    31. evaluate(y_test, y_hat_test, 'test')
    32. score(y_test, y_hat_test)

    模型结构

    1. class Sampling(keras.layers.Layer):
    2. """Uses (z_mean, sigma) to sample z, the vector encoding an engine trajetory."""
    3. def call(self, inputs):
    4. mu, sigma = inputs
    5. batch = tf.shape(mu)[0]
    6. dim = tf.shape(mu)[1]
    7. epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
    8. return mu + tf.exp(0.5 * sigma) * epsilon

    1. class RVE(keras.Model):
    2. def __init__(self, encoder, regressor, decoder=None, **kwargs):
    3. super(RVE, self).__init__(**kwargs)
    4. self.encoder = encoder
    5. self.regressor = regressor
    6. self.total_loss_tracker = keras.metrics.Mean(name="total_loss")
    7. self.kl_loss_tracker = keras.metrics.Mean(name="kl_loss")
    8. self.reg_loss_tracker = keras.metrics.Mean(name="reg_loss")
    9. self.decoder = decoder
    10. if self.decoder!=None:
    11. self.reconstruction_loss_tracker = keras.metrics.Mean(name="reconstruction_loss")
    12. @property
    13. def metrics(self):
    14. if self.decoder!=None:
    15. return [
    16. self.total_loss_tracker,
    17. self.kl_loss_tracker,
    18. self.reg_loss_tracker,
    19. self.reconstruction_loss_tracker
    20. ]
    21. else:
    22. return [
    23. self.total_loss_tracker,
    24. self.kl_loss_tracker,
    25. self.reg_loss_tracker,
    26. ]
    27. def train_step(self, data):
    28. x, target_x = data
    29. with tf.GradientTape() as tape:
    30. # kl loss
    31. mu, sigma, z = self.encoder(x)
    32. kl_loss = -0.5 * (1 + sigma - tf.square(mu) - tf.exp(sigma))
    33. kl_loss = tf.reduce_mean(tf.reduce_sum(kl_loss, axis=1))
    34. # Regressor
    35. reg_prediction = self.regressor(z)
    36. reg_loss = tf.reduce_mean(
    37. keras.losses.mse(target_x, reg_prediction)
    38. )
    39. # Reconstruction
    40. if self.decoder!=None:
    41. reconstruction = self.decoder(z)
    42. reconstruction_loss = tf.reduce_mean(
    43. keras.losses.mse(x, reconstruction)
    44. )
    45. total_loss = kl_loss + reg_loss + reconstruction_loss
    46. self.reconstruction_loss_tracker.update_state(reconstruction_loss)
    47. else:
    48. total_loss = kl_loss + reg_loss
    49. grads = tape.gradient(total_loss, self.trainable_weights)
    50. self.optimizer.apply_gradients(zip(grads, self.trainable_weights))
    51. self.total_loss_tracker.update_state(total_loss)
    52. self.kl_loss_tracker.update_state(kl_loss)
    53. self.reg_loss_tracker.update_state(reg_loss)
    54. return {
    55. "loss": self.total_loss_tracker.result(),
    56. "kl_loss": self.kl_loss_tracker.result(),
    57. "reg_loss": self.reg_loss_tracker.result(),
    58. }
    59. def test_step(self, data):
    60. x, target_x = data
    61. # kl loss
    62. mu, sigma, z = self.encoder(x)
    63. kl_loss = -0.5 * (1 + sigma - tf.square(mu) - tf.exp(sigma))
    64. kl_loss = tf.reduce_mean(tf.reduce_sum(kl_loss, axis=1))
    65. # Regressor
    66. reg_prediction = self.regressor(z)
    67. reg_loss = tf.reduce_mean(
    68. keras.losses.mse(target_x, reg_prediction)
    69. )
    70. # Reconstruction
    71. if self.decoder!=None:
    72. reconstruction = self.decoder(z)
    73. reconstruction_loss = tf.reduce_mean(
    74. keras.losses.mse(x, reconstruction)
    75. )
    76. total_loss = kl_loss + reg_loss + reconstruction_loss
    77. else:
    78. total_loss = kl_loss + reg_loss
    79. return {
    80. "loss": total_loss,
    81. "kl_loss": kl_loss,
    82. "reg_loss": reg_loss,
    83. }

    1. # Set hyperparameters
    2. sequence_length = 200
    3. alpha = 0.2
    4. # Load and preprocess data
    5. df = df # Load dataset
    6. sensors = ['s_max_voltage_discharge', 's_min_voltage_charge', "Time_at_4.15V_s"] # Define the sensors
    7. # Call get_data_with_kfold to get the necessary data
    8. x_train, y_train, x_val, y_val, x_test, y_test = get_data(df1, sensors, sequence_length, alpha)
    9. # from scipy.signal import savgol_filter
    10. # # Apply Savitzky-Golay filter
    11. # x_val_smoothed = savgol_filter(x_val, window_length=4, polyorder=2, axis=0)
    12. # Setup the network parameters:
    13. timesteps = x_train.shape[1]
    14. input_dim = x_train.shape[2]
    15. intermediate_dim = 32
    16. batch_size = 256
    17. latent_dim = 2
    18. masking_value = -99 # used to mask values in sequences with less than 250 cycles until 250 is reached
    19. kernel_regularizer=l1_l2(l1=0.001, l2=0.001)
    20. dropout_rate = 0.1
    21. # --------------------------------- Encoder --------------------------------------
    22. inputs = Input(shape=(timesteps, input_dim,), name='encoder_input')
    23. mask = Masking(mask_value=masking_value)(inputs)
    24. h = Bidirectional(LSTM(intermediate_dim))(mask) # LSTM encoding
    25. mu = Dense(latent_dim, kernel_regularizer = kernel_regularizer)(h) # VAE Z layer
    26. mu = Dropout(dropout_rate)(mu)
    27. sigma = Dense(latent_dim, kernel_regularizer = kernel_regularizer)(h)
    28. sigma = Dropout(dropout_rate)(sigma)
    29. z = Sampling()([mu, sigma])
    30. # Instantiate the encoder model:
    31. encoder = keras.Model(inputs, [mu, sigma, z], name='encoder')
    32. # ------------------------------- Regressor --------------------------------------
    33. reg_latent_inputs = Input(shape=(latent_dim,), name='z_sampling_reg')
    34. reg_intermediate = Dense(16, activation='tanh', kernel_regularizer = kernel_regularizer)(reg_latent_inputs)
    35. reg_intermediate = BatchNormalization()(reg_intermediate)
    36. reg_intermediate = Dropout(dropout_rate)(reg_intermediate)
    37. reg_outputs = Dense(1, name='reg_output', kernel_regularizer = kernel_regularizer)(reg_intermediate)
    38. reg_outputs = Dropout(dropout_rate)(reg_outputs)
    39. # Instantiate the classifier model:
    40. regressor = keras.Model(reg_latent_inputs, reg_outputs, name='regressor')
    41. print("Shape of x_train:", x_train.shape)
    42. print("Shape of y_train:", y_train.shape)
    43. print("Shape of x_val:", x_val.shape)
    44. print("Shape of y_val:", y_val.shape)
    45. print("Shape of x_test:", x_test.shape)
    46. print("Shape of y_test:", len(y_test))

    Shape of x_train: (8795, 200, 3)
    Shape of y_train: (8795, 1)
    Shape of x_val: (1758, 200, 3)
    Shape of y_val: (1758, 1)
    Shape of x_test: (10, 200, 3)
    Shape of y_test: 10

    1. rve = RVE(encoder, regressor)
    2. lr_finder = LRFinder(rve)
    3. rve.compile(optimizer=keras.optimizers.Adam(learning_rate=0.0000001))
    4. # with learning rate growing exponentially from 0.0000001 to 1
    5. lr_finder.find(x_train, y_train, start_lr=0.0000001, end_lr=1, batch_size=batch_size, epochs=10)
    6. # Plot the loss
    7. lr_finder.plot_loss()

    图片

    图片

    开始训练

    1. # Instantiate the RVE model
    2. rve = RVE(encoder, regressor)
    3. #Compile the RVE model with the Adam optimizer
    4. rve.compile(optimizer=keras.optimizers.Adam(0.01))
    5. # Define the early stopping callback
    6. early_stopping = EarlyStopping(monitor='loss', min_delta=3, patience=5, verbose=1, mode='min', restore_best_weights=True)
    7. # Call get_data_with_kfold to get the necessary data
    8. x_train, y_train, x_val, y_val, x_test, y_test = get_data(df1, sensors, sequence_length, alpha)
    9. # Fit the RVE model with the callbacks
    10. rve.fit(x_train, y_train, epochs=500, batch_size=batch_size, validation_data=(x_val, y_val), callbacks=[early_stopping])

    RUL估计

    1. train_mu = viz_latent_space(rve.encoder, np.concatenate((x_train, x_val)), np.concatenate((y_train, y_val)))
    2. test_mu = viz_latent_space(rve.encoder, x_test, y_test)
    3. # Evaluate
    4. y_hat_train = rve.regressor.predict(train_mu)
    5. y_hat_test = rve.regressor.predict(test_mu)
    6. evaluate(np.concatenate((y_train, y_val)), y_hat_train, 'train')
    7. evaluate(y_test, y_hat_test, 'test')

    图片

    图片

    330/330 [==============================] - 0s 1ms/step 1/1 [==============================] - 0s 20ms/step train set RMSE:26.346721649169922, R2:0.9899616368349312 test set RMSE:246.51723899515346, R2:0.5192274671464132


    (246.51723899515346, 0.5192274671464132)

    工学博士,担任《Mechanical System and Signal Processing》《中国电机工程学报》《控制与决策》等期刊审稿专家,擅长领域:现代信号处理,机器学习,深度学习,数字孪生,时间序列分析,设备缺陷检测、设备异常检测、设备智能故障诊断与健康管理PHM等。

  • 相关阅读:
    常用SQL语法总结
    嵌入式Linux入门—Linux多线程编程、互斥量、信号量、条件变量
    iOS15.4来袭:新增“男妈妈”表情及口罩面容解锁、AirTags反跟踪等新功能
    五、《图解HTTP》报文首部和HTTP缓存
    【Buildroot】工具包使用
    Android面试题 - 01
    js实现整数和小数分开并添加不同的样式
    「网页开发|前端开发|Vue」09 Vue状态管理Vuex:让页面根据用户登录状态渲染不同内容
    数据结构之八大排序——简单选择排序
    关于DDD和COLA的一些总结和思考
  • 原文地址:https://blog.csdn.net/weixin_39402231/article/details/139598235