|
|
@@ -1,5 +1,7 @@
|
|
|
+import json
|
|
|
import math
|
|
|
-
|
|
|
+import os
|
|
|
+from datetime import datetime as dt
|
|
|
import tensorflow as tf
|
|
|
import numpy as np
|
|
|
import matplotlib.pyplot as plt
|
|
|
@@ -62,8 +64,8 @@ class EndToEndAutoencoder(tf.keras.Model):
|
|
|
leaky_relu_alpha = 0
|
|
|
relu_clip_val = 1.0
|
|
|
|
|
|
- # layer configuration
|
|
|
- encoding_layers = [
|
|
|
+ # Encoding Neural Network
|
|
|
+ self.encoder = tf.keras.Sequential([
|
|
|
layers.Input(shape=(self.messages_per_block, self.cardinality)),
|
|
|
layers.TimeDistributed(layers.Dense(2 * self.cardinality)),
|
|
|
layers.TimeDistributed(layers.LeakyReLU(alpha=leaky_relu_alpha)),
|
|
|
@@ -72,24 +74,91 @@ class EndToEndAutoencoder(tf.keras.Model):
|
|
|
layers.TimeDistributed(layers.Dense(self.samples_per_symbol, activation='sigmoid')),
|
|
|
# layers.TimeDistributed(layers.Dense(self.samples_per_symbol)),
|
|
|
# layers.TimeDistributed(layers.ReLU(max_value=relu_clip_val))
|
|
|
- ]
|
|
|
- decoding_layers = [
|
|
|
+ ], name="encoding_model")
|
|
|
+
|
|
|
+ # Decoding Neural Network
|
|
|
+ self.decoder = tf.keras.Sequential([
|
|
|
layers.Dense(2 * self.cardinality),
|
|
|
layers.LeakyReLU(alpha=leaky_relu_alpha),
|
|
|
layers.Dense(2 * self.cardinality),
|
|
|
layers.LeakyReLU(alpha=leaky_relu_alpha),
|
|
|
layers.Dense(self.cardinality, activation='softmax')
|
|
|
- ]
|
|
|
+ ], name="decoding_model")
|
|
|
|
|
|
- # Encoding Neural Network
|
|
|
- self.encoder = tf.keras.Sequential([
|
|
|
- *encoding_layers
|
|
|
- ], name="encoding_model")
|
|
|
+ def save_end_to_end(self):
|
|
|
+ # extract all params and save
|
|
|
|
|
|
- # Decoding Neural Network
|
|
|
- self.decoder = tf.keras.Sequential([
|
|
|
- *decoding_layers
|
|
|
- ], name="decoding_model")
|
|
|
+ params = {"fs": self.channel.layers[1].fs,
|
|
|
+ "cardinality": self.cardinality,
|
|
|
+ "samples_per_symbol": self.samples_per_symbol,
|
|
|
+ "messages_per_block": self.messages_per_block,
|
|
|
+ "dispersion_factor": self.channel.layers[1].dispersion_factor,
|
|
|
+ "fiber_length": float(self.channel.layers[1].fiber_length),
|
|
|
+ "fiber_length_stddev": float(self.channel.layers[1].fiber_length_stddev),
|
|
|
+ "lpf_cutoff": self.channel.layers[1].lpf_cutoff,
|
|
|
+ "rx_stddev": self.channel.layers[1].rx_stddev,
|
|
|
+ "sig_avg": self.channel.layers[1].sig_avg,
|
|
|
+ "enob": self.channel.layers[1].enob,
|
|
|
+ "custom_loss_fn": self.custom_loss_fn
|
|
|
+ }
|
|
|
+ dir_str = os.path.join("exports", dt.utcnow().strftime("%Y%m%d-%H%M%S"))
|
|
|
+
|
|
|
+ if not os.path.exists(dir_str):
|
|
|
+ os.makedirs(dir_str)
|
|
|
+
|
|
|
+ with open(os.path.join(dir_str, 'params.json'), 'w') as outfile:
|
|
|
+ json.dump(params, outfile)
|
|
|
+
|
|
|
+ ################################################################################################################
|
|
|
+ # This section exports the weights of the encoder formatted using python variable instantiation syntax
|
|
|
+ ################################################################################################################
|
|
|
+
|
|
|
+ enc_weights, dec_weights = self.extract_weights()
|
|
|
+
|
|
|
+ enc_weights = [x.tolist() for x in enc_weights]
|
|
|
+ dec_weights = [x.tolist() for x in dec_weights]
|
|
|
+
|
|
|
+ enc_w = enc_weights[::2]
|
|
|
+ enc_b = enc_weights[1::2]
|
|
|
+
|
|
|
+ dec_w = dec_weights[::2]
|
|
|
+ dec_b = dec_weights[1::2]
|
|
|
+
|
|
|
+ with open(os.path.join(dir_str, 'enc_weights.py'), 'w') as outfile:
|
|
|
+ outfile.write("enc_weights = ")
|
|
|
+ outfile.write(str(enc_w))
|
|
|
+ outfile.write("\n\nenc_bias = ")
|
|
|
+ outfile.write(str(enc_b))
|
|
|
+
|
|
|
+ with open(os.path.join(dir_str, 'dec_weights.py'), 'w') as outfile:
|
|
|
+ outfile.write("dec_weights = ")
|
|
|
+ outfile.write(str(dec_w))
|
|
|
+ outfile.write("\n\ndec_bias = ")
|
|
|
+ outfile.write(str(dec_b))
|
|
|
+
|
|
|
+ ################################################################################################################
|
|
|
+
|
|
|
+ self.encoder.save(os.path.join(dir_str, 'encoder'))
|
|
|
+ self.decoder.save(os.path.join(dir_str, 'decoder'))
|
|
|
+
|
|
|
+ def extract_weights(self):
|
|
|
+ enc_weights = self.encoder.get_weights()
|
|
|
+ dec_weights = self.encoder.get_weights()
|
|
|
+
|
|
|
+ return enc_weights, dec_weights
|
|
|
+
|
|
|
+ def encode_stream(self, x):
|
|
|
+ enc_weights, dec_weights = self.extract_weights()
|
|
|
+
|
|
|
+ for i in range(len(enc_weights) // 2):
|
|
|
+ x = np.matmul(x, enc_weights[2 * i]) + enc_weights[2 * i + 1]
|
|
|
+
|
|
|
+ if i == len(enc_weights) // 2 - 1:
|
|
|
+ x = tf.keras.activations.sigmoid(x).numpy()
|
|
|
+ else:
|
|
|
+ x = tf.keras.activations.relu(x).numpy()
|
|
|
+
|
|
|
+ return x
|
|
|
|
|
|
def cost(self, y_true, y_pred):
|
|
|
symbol_cost = losses.CategoricalCrossentropy()(y_true, y_pred)
|
|
|
@@ -296,6 +365,12 @@ class EndToEndAutoencoder(tf.keras.Model):
|
|
|
# Apply LPF
|
|
|
lpf_out = lpf(flat_enc)
|
|
|
|
|
|
+ a = np.fft.fft(lpf_out.numpy()).flatten()
|
|
|
+ f = np.fft.fftfreq(a.shape[-1]).flatten()
|
|
|
+
|
|
|
+ plt.plot(f, a)
|
|
|
+ plt.show()
|
|
|
+
|
|
|
# Time axis
|
|
|
t = np.arange(self.messages_per_block * self.samples_per_symbol)
|
|
|
if isinstance(self.channel.layers[1], OpticalChannel):
|
|
|
@@ -314,7 +389,6 @@ class EndToEndAutoencoder(tf.keras.Model):
|
|
|
plt.xlim((t.min(), t.max()))
|
|
|
plt.title(str(val[0, :, 0]))
|
|
|
plt.show()
|
|
|
- pass
|
|
|
|
|
|
def call(self, inputs, training=None, mask=None):
|
|
|
tx = self.encoder(inputs)
|
|
|
@@ -323,52 +397,90 @@ class EndToEndAutoencoder(tf.keras.Model):
|
|
|
return outputs
|
|
|
|
|
|
|
|
|
-SAMPLING_FREQUENCY = 336e9
|
|
|
-CARDINALITY = 32
|
|
|
-SAMPLES_PER_SYMBOL = 32
|
|
|
-MESSAGES_PER_BLOCK = 9
|
|
|
-DISPERSION_FACTOR = -21.7 * 1e-24
|
|
|
-FIBER_LENGTH = 50
|
|
|
-FIBER_LENGTH_STDDEV = 5
|
|
|
+def load_model(model_name=None):
|
|
|
+ if model_name is None:
|
|
|
+ models = os.listdir("exports")
|
|
|
+ if not models:
|
|
|
+ raise Exception("Unable to find a trained model. Please first train and save a model.")
|
|
|
+ model_name = models[-1]
|
|
|
+
|
|
|
+ param_file_path = os.path.join("exports", model_name, "params.json")
|
|
|
+
|
|
|
+ if not os.path.isfile(param_file_path):
|
|
|
+ raise Exception("Invalid File Name/Directory")
|
|
|
+ else:
|
|
|
+ with open(param_file_path, 'r') as param_file:
|
|
|
+ params = json.load(param_file)
|
|
|
+
|
|
|
+ optical_channel = OpticalChannel(fs=params["fs"],
|
|
|
+ num_of_samples=params["messages_per_block"] * params["samples_per_symbol"],
|
|
|
+ dispersion_factor=params["dispersion_factor"],
|
|
|
+ fiber_length=params["fiber_length"],
|
|
|
+ fiber_length_stddev=params["fiber_length_stddev"],
|
|
|
+ lpf_cutoff=params["lpf_cutoff"],
|
|
|
+ rx_stddev=params["rx_stddev"],
|
|
|
+ sig_avg=params["sig_avg"],
|
|
|
+ enob=params["enob"])
|
|
|
+
|
|
|
+ ae_model = EndToEndAutoencoder(cardinality=params["cardinality"],
|
|
|
+ samples_per_symbol=params["samples_per_symbol"],
|
|
|
+ messages_per_block=params["messages_per_block"],
|
|
|
+ channel=optical_channel,
|
|
|
+ custom_loss_fn=params["custom_loss_fn"])
|
|
|
+
|
|
|
+ ae_model.encoder = tf.keras.models.load_model(os.path.join("exports", model_name, "encoder"))
|
|
|
+ ae_model.decoder = tf.keras.models.load_model(os.path.join("exports", model_name, "decoder"))
|
|
|
+
|
|
|
+ return ae_model, params
|
|
|
+
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
- stddevs = [0, 1, 5, 10]
|
|
|
- legend = []
|
|
|
-
|
|
|
- for s in stddevs:
|
|
|
- optical_channel = OpticalChannel(fs=SAMPLING_FREQUENCY,
|
|
|
- num_of_samples=MESSAGES_PER_BLOCK * SAMPLES_PER_SYMBOL,
|
|
|
- dispersion_factor=DISPERSION_FACTOR,
|
|
|
- fiber_length=FIBER_LENGTH,
|
|
|
- fiber_length_stddev=s,
|
|
|
- lpf_cutoff=32e9,
|
|
|
- rx_stddev=0.01,
|
|
|
- sig_avg=0.5,
|
|
|
- enob=10)
|
|
|
-
|
|
|
- ae_model = EndToEndAutoencoder(cardinality=CARDINALITY,
|
|
|
- samples_per_symbol=SAMPLES_PER_SYMBOL,
|
|
|
- messages_per_block=MESSAGES_PER_BLOCK,
|
|
|
- channel=optical_channel,
|
|
|
- custom_loss_fn=True)
|
|
|
-
|
|
|
- print(ae_model.snr)
|
|
|
-
|
|
|
- ae_model.train(num_of_blocks=3e5, epochs=5)
|
|
|
- ae_model.test(length_plot=True, plt_show=False)
|
|
|
- # plt.legend(['{} +/- {}'.format(FIBER_LENGTH, s)])
|
|
|
-
|
|
|
- legend.append('{} +/- {}'.format(FIBER_LENGTH, s))
|
|
|
-
|
|
|
- plt.legend(legend)
|
|
|
- plt.show()
|
|
|
- plt.savefig('ber_vs_length.eps', format='eps')
|
|
|
-
|
|
|
- # ae_model.view_encoder()
|
|
|
- # ae_model.view_sample_block()
|
|
|
- # # ae_model.summary()
|
|
|
- # ae_model.encoder.summary()
|
|
|
- # ae_model.channel.summary()
|
|
|
- # ae_model.decoder.summary()
|
|
|
+ params = {"fs": 336e9,
|
|
|
+ "cardinality": 32,
|
|
|
+ "samples_per_symbol": 32,
|
|
|
+ "messages_per_block": 9,
|
|
|
+ "dispersion_factor": (-21.7 * 1e-24),
|
|
|
+ "fiber_length": 50,
|
|
|
+ "fiber_length_stddev": 1,
|
|
|
+ "lpf_cutoff": 32e9,
|
|
|
+ "rx_stddev": 0.01,
|
|
|
+ "sig_avg": 0.5,
|
|
|
+ "enob": 8,
|
|
|
+ "custom_loss_fn": True
|
|
|
+ }
|
|
|
+
|
|
|
+ force_training = False
|
|
|
+
|
|
|
+ model_save_name = ""
|
|
|
+ param_file_path = os.path.join("exports", model_save_name, "params.json")
|
|
|
+
|
|
|
+ if os.path.isfile(param_file_path) and not force_training:
|
|
|
+ print("Importing model {}".format(model_save_name))
|
|
|
+ with open(param_file_path, 'r') as file:
|
|
|
+ params = json.load(file)
|
|
|
+
|
|
|
+ optical_channel = OpticalChannel(fs=params["fs"],
|
|
|
+ num_of_samples=params["messages_per_block"] * params["samples_per_symbol"],
|
|
|
+ dispersion_factor=params["dispersion_factor"],
|
|
|
+ fiber_length=params["fiber_length"],
|
|
|
+ fiber_length_stddev=params["fiber_length_stddev"],
|
|
|
+ lpf_cutoff=params["lpf_cutoff"],
|
|
|
+ rx_stddev=params["rx_stddev"],
|
|
|
+ sig_avg=params["sig_avg"],
|
|
|
+ enob=params["enob"])
|
|
|
+
|
|
|
+ ae_model = EndToEndAutoencoder(cardinality=params["cardinality"],
|
|
|
+ samples_per_symbol=params["samples_per_symbol"],
|
|
|
+ messages_per_block=params["messages_per_block"],
|
|
|
+ channel=optical_channel,
|
|
|
+ custom_loss_fn=params["custom_loss_fn"])
|
|
|
+
|
|
|
+ if os.path.isfile(param_file_path) and not force_training:
|
|
|
+ ae_model.encoder = tf.keras.models.load_model(os.path.join("exports", model_save_name, "encoder"))
|
|
|
+ ae_model.decoder = tf.keras.models.load_model(os.path.join("exports", model_save_name, "decoder"))
|
|
|
+ else:
|
|
|
+ ae_model.train(num_of_blocks=1e5, epochs=5)
|
|
|
+ ae_model.save_end_to_end()
|
|
|
+
|
|
|
pass
|