{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"},{"sourceId":2280,"sourceType":"datasetVersion","datasetId":1272}],"dockerImageVersionId":30761,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **Libraries**","metadata":{}},{"cell_type":"code","source":"!pip install imutils\nimport numpy as np\nimport random\nimport cv2\nimport os\nimport json\nfrom imutils import paths\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import LabelBinarizer\nfrom sklearn.metrics import accuracy_score\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Activation\nfrom tensorflow.keras.optimizers import SGD\nfrom tensorflow.keras.callbacks import LearningRateScheduler\nfrom tensorflow.keras import backend as K\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Auxilary Functions**","metadata":{}},{"cell_type":"code","source":"def load(paths, verbose=-1):\n    data = []\n    labels = []\n    for (i, imgpath) in enumerate(paths):\n        im_gray = cv2.imread(imgpath, cv2.IMREAD_GRAYSCALE)\n        image = np.array(im_gray).flatten()\n        label = imgpath.split(os.path.sep)[-2]\n        data.append(image / 255.0)\n        labels.append(label)\n        if verbose > 0 and i > 0 and (i + 1) % verbose == 0:\n            print(f\"[INFO] processed {i + 1}/{len(paths)}\")\n    return data, labels\n\ndef create_clients(image_list, label_list, num_clients=10, initial='clients'):\n    client_names = [f'{initial}_{i + 1}' for i in range(num_clients)]\n    data = list(zip(image_list, label_list))\n    random.shuffle(data)\n    size = len(data) // num_clients + 1\n    shards = [data[i:i + size] for i in range(0, size * num_clients, size)]\n    assert len(shards) == len(client_names)\n    return {client_names[i]: shards[i] for i in range(len(client_names))}\n\ndef batch_data(data_shard, bs=32):\n    data, label = zip(*data_shard)\n    dataset = tf.data.Dataset.from_tensor_slices((list(data), list(label)))\n    return dataset.shuffle(len(label)).batch(bs)\n\ndef weight_scaling_factor(clients_trn_data, client_name, bs):\n    client_names = list(clients_trn_data.keys())\n    global_count = sum([len(clients_trn_data[client_name]) for client_name in client_names]) * bs\n    local_count = len(clients_trn_data[client_name]) * bs\n    return local_count / global_count\n\ndef scale_model_weights(weight, scalar):\n    return [scalar * w for w in weight]\n\ndef sum_scaled_weights(scaled_weight_list):\n    avg_grad = []\n    for grad_list_tuple in zip(*scaled_weight_list):\n        layer_mean = tf.math.reduce_sum(grad_list_tuple, axis=0)\n        avg_grad.append(layer_mean)\n    return avg_grad\n\ndef test_model(X_test, Y_test, model, comm_round):\n    cce = tf.keras.losses.CategoricalCrossentropy(from_logits=True)\n    logits = model.predict(X_test)\n    loss = cce(Y_test, logits).numpy()\n    acc = accuracy_score(np.argmax(logits, axis=1), np.argmax(Y_test, axis=1))\n    print(f'comm_round: {comm_round} | global_acc: {acc:.3%} | global_loss: {loss}')\n    return acc, loss\n\n#initializing the model specifics\ndef create_optimizer(lr):\n    return SGD(learning_rate=lr, momentum=0.9)\n\ndef lr_schedule(epoch, lr):\n    decay_factor = 0.9\n    decay_epochs = 10\n    if epoch % decay_epochs == 0:\n        lr *= decay_factor\n    return lr\n\ndef schedule_with_comms_round(comms_round):\n    def wrapped_schedule(epoch, lr):\n        return lr_schedule(epoch, lr)\n    return wrapped_schedule","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Model Definition**","metadata":{}},{"cell_type":"code","source":"class SimpleMLP:\n    @staticmethod\n    def build(shape, classes):\n        model = Sequential([\n            Dense(200, input_shape=(shape,)),\n            Activation(\"relu\"),\n            Dense(200),\n            Activation(\"relu\"),\n            Dense(classes),\n            Activation(\"softmax\")\n        ])\n        return model","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **JSON weight storage and autoencoder**","metadata":{}},{"cell_type":"code","source":"# def extract_weights_for_layer(layer_weights):\n#     return layer_weights.flatten().tolist()\n\n# def store_weights_json(clients, num_epochs, global_model, file_name='client_weights.txt'):\n#     client_data = {}\n#     for client in clients:\n#         client_data[client] = {}\n#         for epoch in range(num_epochs):\n#             client_data[client][f'epoch_{epoch + 1}'] = {}\n#             for layer_index, layer in enumerate(global_model.layers):\n#                 weights, biases = layer.get_weights()\n#                 flattened_weights = extract_weights_for_layer(weights)\n#                 flattened_biases = extract_weights_for_layer(biases)\n#                 client_data[client][f'epoch_{epoch + 1}'][f'layer_{layer_index + 1}'] = {\n#                     'weights': flattened_weights,\n#                     'biases': flattened_biases\n#                 }\n                \n# # Write the JSON content into a .txt file\n#     with open(file_name, 'w') as txt_file:\n#         json.dump(client_data, txt_file)\n#     print(f\"Client weights stored in {file_name}\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Loading weights for Auto-encoder input**","metadata":{}},{"cell_type":"code","source":"# def load_weights_from_txt(file_name):\n#     with open(file_name, 'r') as txt_file:\n#         return json.load(txt_file)\n\n# def prepare_autoencoder_input(json_data):\n#     vectors = []\n#     for client, epochs in json_data.items():\n#         for epoch, layers in epochs.items():\n#             for layer, params in layers.items():\n#                 # Combine weights and biases into one vector\n#                 vector = params['weights'] + params['biases']\n#                 vectors.append(vector)\n#     return np.array(vectors)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Auto-encoder Model**","metadata":{}},{"cell_type":"code","source":"# autoencoder_input_dim = 400  # 200 neurons * 2 layers\n# input_layer = tf.keras.Input(shape=(autoencoder_input_dim,))\n# encoded = Dense(100, activation='relu')(input_layer)  # Reduce to 100 dimensions\n# decoded = Dense(autoencoder_input_dim, activation='sigmoid')(encoded)  # Reconstruct the input\n\n# autoencoder = tf.keras.Model(input_layer, decoded)\n# autoencoder.compile(optimizer='adam', loss='binary_crossentropy')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Datapath and Dataset**","metadata":{}},{"cell_type":"code","source":"img_path = '/kaggle/input/mnistasjpg/trainingSet/trainingSet'\nimage_paths = list(paths.list_images(img_path))\nimage_list, label_list = load(image_paths, verbose=10000)\n\n# Binarize the labels and split the data\nlb = LabelBinarizer()\nlabel_list = lb.fit_transform(label_list)\nX_train, X_test, y_train, y_test = train_test_split(image_list, label_list, test_size=0.1, random_state=42)\n\n# Create clients and batch their data\nclients = create_clients(X_train, y_train, num_clients=10, initial='client')\nclients_batched = {client: batch_data(data) for client, data in clients.items()}\n\n# Batch the test data\ntest_batched = tf.data.Dataset.from_tensor_slices((X_test, y_test)).batch(len(y_test))\n\ncomms_round = 50\nlr = 0.01\nloss = 'categorical_crossentropy'\nmetrics = ['accuracy']\n\n# Initialize global model\nsmlp_global = SimpleMLP()\nglobal_model = smlp_global.build(784, 10)\n\n# JSON weight storage\nclient_weights = {}","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Federated Training**","metadata":{}},{"cell_type":"code","source":"for comm_round in range(comms_round):\n    global_weights = global_model.get_weights()\n    scaled_local_weight_list = []\n    client_names = list(clients_batched.keys())\n    random.shuffle(client_names)\n\n    for client in client_names:\n        smlp_local = SimpleMLP()\n        local_model = smlp_local.build(784, 10)\n        optimizer = SGD(learning_rate=lr, momentum=0.9)\n        local_model.compile(loss=loss, optimizer=optimizer, metrics=metrics)\n        local_model.set_weights(global_weights)\n        local_model.fit(clients_batched[client], epochs=1, verbose=0)\n\n        scaling_factor = weight_scaling_factor(clients_batched, client, bs=32)\n        scaled_weights = scale_model_weights(local_model.get_weights(), scaling_factor)\n        scaled_local_weight_list.append(scaled_weights)\n\n        # Store client weights\n        client_weights_data[client] = {\n            'weights': [w.tolist() for w in scaled_weights],\n            'comm_round': comm_round\n        }\n        K.clear_session()\n\n    average_weights = sum_scaled_weights(scaled_local_weight_list)\n    global_model.set_weights(average_weights)\n\n    for X_test, Y_test in test_batched:\n        global_acc, global_loss = test_model(X_test, Y_test, global_model, comm_round)\n\n# Save weights to JSON file\nwith open('client_weights.json', 'w') as json_file:\n    json.dump(client_weights_data, json_file)\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Prepare Data for Auto-encoder**","metadata":{}},{"cell_type":"code","source":"# Read JSON file for autoencoder input\nwith open('client_weights.json', 'r') as json_file:\n    client_weights_data = json.load(json_file)\n\n# Prepare input for autoencoder\nautoencoder_input = []\nfor client, data in client_weights_data.items():\n    for weight in data['weights']:\n        autoencoder_input.append(weight)\n\nautoencoder_input = np.array(autoencoder_input)\n\n# Define and train autoencoder\nautoencoder = Sequential([\n    Dense(100, activation='relu', input_shape=(400,)),  # Adjust input shape as necessary\n    Dense(50, activation='relu'),\n    Dense(100, activation='relu'),\n    Dense(400, activation='sigmoid')  # Output shape matches input shape\n])\n\nautoencoder.compile(optimizer='adam', loss='mse')\nautoencoder.fit(autoencoder_input, autoencoder_input, epochs=50, batch_size=10, verbose=1)\n\n# Get encoded output\nencoded_output = autoencoder.predict(autoencoder_input)\n\n# Save encoded output to CSV\nencoded_df = pd.DataFrame(encoded_output)\nencoded_df.to_csv('encoded_client_weights.csv', index=False)\n\nprint(\"Encoded client weights saved to 'encoded_client_weights.csv'.\")","metadata":{},"execution_count":null,"outputs":[]}]}