├── Federated (linear regression + blockchain) ├── __pycache__ │ ├── backprop.cpython-38.pyc │ └── blockchain.cpython-38.pyc ├── a.out ├── backprop.py ├── backprop.pyc ├── backprop_modified.py ├── blockchain.py ├── client1.py ├── client2.py ├── data.csv ├── server.py └── stats.txt ├── Federated (linear regression) ├── backprop.py ├── client1.py ├── client2.py ├── data.csv ├── server.py └── statistics.txt ├── Need for Blockchain ├── __pycache__ │ └── backprop.cpython-38.pyc ├── a.out ├── backprop.py ├── backprop.pyc ├── backprop_modified.py ├── client1.py ├── client2.py ├── data.csv ├── model_logs ├── server.py └── stats.txt └── README.md /Federated (linear regression + blockchain)/__pycache__/backprop.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repeatedd/federated-learning-blockchain/57fc408ebb990130d128e05df63538669e1f8b0f/Federated (linear regression + blockchain)/__pycache__/backprop.cpython-38.pyc -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/__pycache__/blockchain.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repeatedd/federated-learning-blockchain/57fc408ebb990130d128e05df63538669e1f8b0f/Federated (linear regression + blockchain)/__pycache__/blockchain.cpython-38.pyc -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repeatedd/federated-learning-blockchain/57fc408ebb990130d128e05df63538669e1f8b0f/Federated (linear regression + blockchain)/a.out -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/backprop.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | # from tqdm._tqdm_notebook import tqdm_notebook as tqdm 3 | # tqdm().pandas() 4 | 5 | class Layer(): 6 | 7 | def __init__(self, model, f, d_f, input_dims = None, output_dims = None, input_layer=False, output_layer=False, learning_rate=0.001): 8 | 9 | self.model = model 10 | self.input_dims = input_dims 11 | self.output_dims = output_dims 12 | self.learning_rate = learning_rate 13 | 14 | # Parameters 15 | self.a = None 16 | self.z = None 17 | self.W = None 18 | self.b = None 19 | 20 | self.dW = None 21 | self.db = None 22 | self.da = None 23 | self.dz = None 24 | 25 | self.input_layer = input_layer 26 | self.output_layer = output_layer 27 | 28 | # Activation Functions 29 | self.f = f 30 | self.d_f = d_f 31 | 32 | # Adjacent layers set during backpropagation 33 | self.next_layer = None 34 | self.prev_layer = None 35 | 36 | 37 | def random_init(self): 38 | 39 | # Kaiming Weight Initialization 40 | self.W = np.random.randn(self.output_dims, self.input_dims)*np.sqrt(2)/np.sqrt(self.input_dims) 41 | 42 | # Xavier Weight Initialization 43 | # B = np.sqrt(6)/np.sqrt(self.input_dims + self.output_dims) 44 | # self.W = np.random.uniform(low=-B , high=B ,size=(self.output_dims, self.input_dims)) 45 | 46 | self.b = np.zeros(shape=(self.output_dims, 1)) 47 | 48 | 49 | def get_prev_a(self): 50 | if self.input_layer: 51 | return self.model.data 52 | return self.prev_layer.a 53 | 54 | 55 | def forward_pass(self): 56 | prev_a = self.get_prev_a() 57 | self.z = self.W.dot(prev_a) + self.b 58 | self.a = self.f(self.z) 59 | 60 | 61 | def backpropagate(self): 62 | prev_a = self.get_prev_a() 63 | 64 | if self.output_layer: 65 | delta = self.model.calc_d_J(self.a) 66 | else: 67 | delta = self.next_layer.da 68 | 69 | m = prev_a.shape[1] 70 | 71 | self.dz = delta * self.d_f(self.z) 72 | self.dW = self.dz.dot(prev_a.T)/m 73 | self.db = np.sum(self.dz, axis=1, keepdims=True) 74 | self.da = self.W.T.dot(self.dz) 75 | 76 | def learn(self): 77 | self.W = self.W - self.learning_rate * self.dW 78 | self.b = self.b - self.learning_rate * self.db 79 | 80 | class NeuralNetwork(): 81 | 82 | def __init__(self, architecture, input_size, cost_function, train_data=None, train_labels=None, learning_rate=0.001): 83 | 84 | self.learning_rate = learning_rate 85 | self.architecture = architecture 86 | self.cost_function = cost_function 87 | 88 | # Create Layers 89 | self.layers = self.create_layers(architecture, input_size) 90 | 91 | # Data 92 | self.data = train_data 93 | self.labels = train_labels 94 | 95 | # Cost Function 96 | self.J, self.d_J = cost_functions[cost_function] 97 | 98 | 99 | def calc_J(self, y_hat): 100 | return self.J(self.labels, y_hat) 101 | 102 | 103 | def calc_d_J(self, y_hat): 104 | return self.d_J(self.labels, y_hat) 105 | 106 | 107 | def calc_accuracy(self, test_data, test_labels, error_func="MSE"): 108 | self.data = test_data 109 | self.labels = test_labels 110 | 111 | # Forward Pass and get output 112 | self.forward_pass() 113 | y_hat = self.layers[-1].a 114 | 115 | if error_func == "MSE": 116 | # return np.sqrt(np.sum(y_hat-self.labels))/self.labels.shape[1] 117 | return np.sum((self.labels - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2) 118 | elif error_func == "MAE": 119 | return np.sum(np.abs(y_hat-self.labels))/self.labels.shape[1] 120 | elif error_func == "RMSE": 121 | return np.sqrt(np.sum((self.labels - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2)) 122 | else: 123 | y_pred = np.where(y_hat > 0.5, 1, 0) 124 | return (y_pred == self.labels).mean() 125 | 126 | def create_layers(self, architecture, input_size): 127 | 128 | layers = [] 129 | 130 | for i, config in enumerate(architecture): 131 | input_dims = input_size if i == 0 else layers[-1].output_dims 132 | output_dims = config["num_nodes"] 133 | f, d_f = activation_functions[config["activation"]] 134 | layer = Layer(self, f, d_f, input_dims, output_dims, input_layer=(i==0), output_layer=(i==len(architecture)-1), learning_rate=self.learning_rate) 135 | 136 | if i != 0: 137 | layers[-1].next_layer = layer 138 | layer.prev_layer = layers[-1] 139 | 140 | 141 | layers.append(layer) 142 | 143 | for layer in layers: 144 | layer.random_init() 145 | 146 | return layers 147 | 148 | def add_data(self, train_data, train_labels): 149 | self.data = train_data 150 | self.labels = train_labels 151 | 152 | def forward_pass(self): 153 | for layer in self.layers: 154 | layer.forward_pass() 155 | 156 | def backward_pass(self): 157 | for layer in reversed(self.layers): 158 | layer.backpropagate() 159 | 160 | def learn(self): 161 | for layer in self.layers: 162 | layer.learn() 163 | 164 | def train(self, epochs): 165 | history = [] 166 | for i in range(epochs): 167 | self.forward_pass() 168 | cost = self.calc_J(self.layers[-1].a) 169 | history.append(cost) 170 | # if i % 50 == 0: 171 | # print ("Cost after iteration %i: %f" %(i, cost)) 172 | self.backward_pass() 173 | self.learn() 174 | 175 | # Training done. Return history 176 | return history 177 | 178 | # COST FUNCTIONS 179 | 180 | def cross_entropy_sigmoid(y, y_hat): 181 | m = y.shape[1] 182 | cost = (1./m) * (-np.dot(y,np.log(y_hat).T) - np.dot(1-y, np.log(1-y_hat).T)) 183 | cost = np.squeeze(cost) 184 | return cost 185 | 186 | 187 | def cross_entropy_sigmoid_derivative(y, y_hat): 188 | m = y.shape[1] 189 | return (-(np.divide(y, y_hat) - np.divide(1 - y, 1 - y_hat))) 190 | 191 | 192 | def mean_squared(y, y_hat): 193 | return np.sum((y - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2) 194 | 195 | def d_mean_squared(y, y_hat): 196 | return (y_hat - y) 197 | 198 | 199 | cost_functions = {"cross_entropy_sigmoid" : (cross_entropy_sigmoid, cross_entropy_sigmoid_derivative), 200 | "mean_squared" : (mean_squared, d_mean_squared) 201 | } 202 | 203 | # ACTIVATION FUNCTIONS 204 | 205 | import numpy as np 206 | 207 | def sigmoid(x): 208 | s = 1/(1+np.exp(-x)) 209 | return s 210 | 211 | def d_sigmoid(x): 212 | s = sigmoid(x) 213 | return s*(1-s) 214 | 215 | def relu(x): 216 | return np.maximum(0,x) 217 | 218 | def d_relu(x): 219 | r = np.where(x > 0, 1, 0) 220 | return r 221 | 222 | def tanh(x): 223 | return np.tanh(x) 224 | 225 | def d_tanh(x): 226 | d = tanh(x) 227 | return 1 - d*d 228 | 229 | 230 | activation_functions = {"sigmoid" : (sigmoid, d_sigmoid) , "relu" : (relu, d_relu), "tanh" : (tanh, d_tanh)} 231 | 232 | """# Application on Cancer Dataset""" 233 | 234 | # import matplotlib.pyplot as plt 235 | # from sklearn.model_selection import train_test_split 236 | # from sklearn.datasets import load_breast_cancer 237 | 238 | # X, y = load_breast_cancer(return_X_y=True) 239 | # y = y.reshape((len(y), 1)) 240 | 241 | # # Split Data 242 | # train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2) 243 | # train_X = train_X.T 244 | # test_X = test_X.T 245 | 246 | # # Normalize 247 | # mean = np.mean(train_X, axis = 1, keepdims=True) 248 | # std_dev = np.std(train_X, axis = 1, keepdims=True) 249 | # train_X = (train_X - mean)/std_dev 250 | # test_X = (test_X - mean)/std_dev 251 | 252 | # train_y = train_y.T 253 | # test_y = test_y.T 254 | 255 | # train_X.shape, train_y.shape, test_X.shape, test_y.shape 256 | 257 | # description = [{"num_nodes" : 100, "activation" : "relu"}, 258 | # {"num_nodes" : 50, "activation" : "relu"}, 259 | # {"num_nodes" : 1, "activation" : "sigmoid"}] 260 | 261 | # model = NeuralNetwork(description,30,"cross_entropy_sigmoid", train_X, train_y, learning_rate=0.001) 262 | 263 | # history = model.train(1000) 264 | 265 | # plt.plot(history) 266 | 267 | # acc = model.calc_accuracy(train_X, train_y) 268 | # print("Accuracy of the model on the training set is = {}".format(acc)) 269 | 270 | # acc = model.calc_accuracy(test_X, test_y) 271 | # print("Accuracy of the model on the test set is = {}".format(acc)) 272 | 273 | -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/backprop.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repeatedd/federated-learning-blockchain/57fc408ebb990130d128e05df63538669e1f8b0f/Federated (linear regression + blockchain)/backprop.pyc -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/backprop_modified.py: -------------------------------------------------------------------------------- 1 | import backprop as bp 2 | import numpy as np 3 | import pandas as pd 4 | import matplotlib.pyplot as plt 5 | from sklearn.model_selection import train_test_split 6 | from sklearn.datasets import load_breast_cancer 7 | 8 | 9 | df = pd.read_csv('data.csv') 10 | 11 | X = np.array(df.drop('charges', axis=1)) 12 | y = np.array(df['charges']) 13 | # X, y = load_breast_cancer(return_X_y=True) 14 | y = y.reshape((len(y), 1)) 15 | print(X.shape) 16 | 17 | # Split Data 18 | train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2) 19 | train_X = train_X.T 20 | test_X = test_X.T 21 | 22 | print(train_X.shape) 23 | # Normalize 24 | mean = np.mean(train_X, axis = 1, keepdims=True) 25 | std_dev = np.std(train_X, axis = 1, keepdims=True) 26 | train_X = (train_X - mean)/std_dev 27 | test_X = (test_X - mean)/std_dev 28 | 29 | train_y = train_y.T 30 | test_y = test_y.T 31 | 32 | train_X.shape, train_y.shape, test_X.shape, test_y.shape 33 | 34 | description = [{"num_nodes" : 12, "activation" : "relu"}, 35 | # {"num_nodes" : 12, "activation" : "relu"}, 36 | {"num_nodes" : 1, "activation" : "relu"}] 37 | 38 | model = bp.NeuralNetwork(description,12,"mean_squared", train_X, train_y, learning_rate=0.001) 39 | 40 | for i in range(len(model.layers)): 41 | print(model.layers[i].W) 42 | print(model.layers[i].b) 43 | 44 | history = model.train(2000) 45 | 46 | plt.plot(history) 47 | 48 | acc = model.calc_accuracy(train_X, train_y, "RMSE") 49 | print("MSE on the training set is = {}".format(acc)) 50 | 51 | acc = model.calc_accuracy(test_X, test_y,"RMSE") 52 | print("MSE on the test set is = {}".format(acc)) 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/blockchain.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha256 2 | import json 3 | import time 4 | import pickle 5 | import dill 6 | 7 | from flask import Flask, request 8 | import requests 9 | 10 | 11 | class Block: 12 | def __init__(self, index, cli_model, fin_model, timestamp, previous_hash, cli, nonce=0): 13 | self.index = index 14 | self.cli_model = cli_model 15 | self.fin_model = fin_model 16 | self.cli = cli 17 | self.timestamp = timestamp 18 | self.previous_hash = previous_hash 19 | self.nonce = nonce 20 | 21 | def compute_hash(self): 22 | """ 23 | A function that return the hash of the block contents. 24 | """ 25 | temp_block = self 26 | temp = [] 27 | temp.append(self.index) 28 | temp.append(self.cli) 29 | temp.append(self.timestamp) 30 | temp.append(self.previous_hash) 31 | temp.append(self.nonce) 32 | if temp_block.cli_model != 0: 33 | for i in range(len(temp_block.cli_model.layers)): 34 | temp.append(temp_block.cli_model.layers[i].W.tolist()) 35 | temp.append(temp_block.cli_model.layers[i].b.tolist()) 36 | 37 | block_bytes = json.dumps(temp) 38 | return sha256(block_bytes.encode()).hexdigest() 39 | 40 | 41 | class Blockchain: 42 | # difficulty of our PoW algorithm 43 | difficulty = 1 44 | 45 | def __init__(self): 46 | self.unconfirmed_transactions = [] 47 | self.chain = [] 48 | 49 | def create_genesis_block(self): 50 | """ 51 | A function to generate genesis block and appends it to 52 | the chain. The block has index 0, previous_hash as 0, and 53 | a valid hash. 54 | """ 55 | genesis_block = Block(0, 0, 0, 0, 0, "0") 56 | genesis_block.hash = genesis_block.compute_hash() 57 | self.chain.append(genesis_block) 58 | 59 | @property 60 | def last_block(self): 61 | return self.chain[-1] 62 | 63 | def add_block(self, block, proof): 64 | """ 65 | A function that adds the block to the chain after verification. 66 | Verification includes: 67 | * Checking if the proof is valid. 68 | * The previous_hash referred in the block and the hash of latest block 69 | in the chain match. 70 | """ 71 | previous_hash = self.last_block.hash 72 | if previous_hash != block.previous_hash: 73 | return False 74 | if not Blockchain.is_valid_proof(block, proof): 75 | return False 76 | # print("reached") 77 | block.hash = proof 78 | self.chain.append(block) 79 | return self 80 | 81 | def add_blocks(self, chain_dump): 82 | """ 83 | Add the blocks coming from server 84 | after verifying them 85 | """ 86 | for idx, block_data in enumerate(chain_dump): 87 | # if idx == 0: 88 | # continue # skip genesis block 89 | block = Block(block_data.index, 90 | block_data.cli_model, 91 | block_data.fin_model, 92 | block_data.cli, 93 | block_data.timestamp, 94 | block_data.previous_hash, 95 | block_data.nonce) 96 | proof = block_data.hash 97 | added = self.add_block(block, proof) 98 | if not added: 99 | raise Exception("The chain dump is tampered!!") 100 | 101 | @staticmethod 102 | def proof_of_work(block): 103 | """ 104 | Function that tries different values of nonce to get a hash 105 | that satisfies our difficulty criteria. 106 | """ 107 | block.nonce = 0 108 | 109 | computed_hash = block.compute_hash() 110 | while not computed_hash.startswith('0' * Blockchain.difficulty): 111 | block.nonce += 1 112 | computed_hash = block.compute_hash() 113 | 114 | return computed_hash 115 | 116 | def add_new_transaction(self, transaction): 117 | self.unconfirmed_transactions.append(transaction) 118 | 119 | @classmethod 120 | def is_valid_proof(cls, block, block_hash): 121 | """ 122 | Check if block_hash is valid hash of block and satisfies 123 | the difficulty criteria. 124 | print(block.__dict__) 125 | """ 126 | print("hash calculated", block.compute_hash()) 127 | # return True 128 | 129 | return (block_hash.startswith('0' * Blockchain.difficulty) and 130 | block_hash == block.compute_hash()) 131 | 132 | @classmethod 133 | def check_chain_validity(cls, chain): 134 | result = True 135 | previous_hash = "0" 136 | 137 | for block in chain: 138 | block_hash = block.hash 139 | # remove the hash field to recompute the hash again 140 | # using `compute_hash` method. 141 | delattr(block, "hash") 142 | 143 | if not cls.is_valid_proof(block, block_hash) or \ 144 | previous_hash != block.previous_hash: 145 | result = False 146 | break 147 | 148 | block.hash, previous_hash = block_hash, block_hash 149 | 150 | return result 151 | 152 | # def mine(self): 153 | # """ 154 | # This function serves as an interface to add the pending 155 | # transactions to the blockchain by adding them to the block 156 | # and figuring out Proof Of Work. 157 | # """ 158 | # if not self.unconfirmed_transactions: 159 | # return False 160 | 161 | # last_block = self.last_block 162 | 163 | # new_block = Block(index=last_block.index + 1, 164 | # transactions=self.unconfirmed_transactions, 165 | # timestamp=time.time(), 166 | # previous_hash=last_block.hash) 167 | 168 | # proof = self.proof_of_work(new_block) 169 | # self.add_block(new_block, proof) 170 | 171 | # self.unconfirmed_transactions = [] 172 | 173 | # return True 174 | 175 | 176 | 177 | 178 | # app = Flask(__name__) 179 | 180 | # the node's copy of blockchain 181 | # blockchain = Blockchain() 182 | # blockchain.create_genesis_block() 183 | 184 | # # the address to other participating members of the network 185 | # peers = set() 186 | 187 | 188 | # endpoint to submit a new transaction. This will be used by 189 | # our application to add new data (posts) to the blockchain 190 | # @app.route('/new_transaction', methods=['POST']) 191 | # def new_transaction(): 192 | # tx_data = request.get_json() 193 | # required_fields = ["author", "content"] 194 | 195 | # for field in required_fields: 196 | # if not tx_data.get(field): 197 | # return "Invalid transaction data", 404 198 | 199 | # tx_data["timestamp"] = time.time() 200 | 201 | # blockchain.add_new_transaction(tx_data) 202 | 203 | # return "Success", 201 204 | 205 | 206 | # endpoint to return the node's copy of the chain. 207 | # Our application will be using this endpoint to query 208 | # all the posts to display. 209 | # @app.route('/chain', methods=['GET']) 210 | # def get_chain(): 211 | # chain_data = [] 212 | # for block in blockchain.chain: 213 | # chain_data.append(block.__dict__) 214 | # return json.dumps({"length": len(chain_data), 215 | # "chain": chain_data, 216 | # "peers": list(peers)}) 217 | 218 | 219 | # endpoint to request the node to mine the unconfirmed 220 | # transactions (if any). We'll be using it to initiate 221 | # a command to mine from our application itself. 222 | # @app.route('/mine', methods=['GET']) 223 | # def mine_unconfirmed_transactions(): 224 | # result = blockchain.mine() 225 | # if not result: 226 | # return "No transactions to mine" 227 | # else: 228 | # # Making sure we have the longest chain before announcing to the network 229 | # chain_length = len(blockchain.chain) 230 | # consensus() 231 | # if chain_length == len(blockchain.chain): 232 | # # announce the recently mined block to the network 233 | # announce_new_block(blockchain.last_block) 234 | # return "Block #{} is mined.".format(blockchain.last_block.index) 235 | 236 | 237 | # # endpoint to add new peers to the network. 238 | # @app.route('/register_node', methods=['POST']) 239 | # def register_new_peers(): 240 | # node_address = request.get_json()["node_address"] 241 | # if not node_address: 242 | # return "Invalid data", 400 243 | 244 | # # Add the node to the peer list 245 | # peers.add(node_address) 246 | 247 | # # Return the consensus blockchain to the newly registered node 248 | # # so that he can sync 249 | # return get_chain() 250 | 251 | 252 | # @app.route('/register_with', methods=['POST']) 253 | # def register_with_existing_node(): 254 | # """ 255 | # Internally calls the `register_node` endpoint to 256 | # register current node with the node specified in the 257 | # request, and sync the blockchain as well as peer data. 258 | # """ 259 | # node_address = request.get_json()["node_address"] 260 | # if not node_address: 261 | # return "Invalid data", 400 262 | 263 | # data = {"node_address": request.host_url} 264 | # headers = {'Content-Type': "application/json"} 265 | 266 | # # Make a request to register with remote node and obtain information 267 | # response = requests.post(node_address + "/register_node", 268 | # data=json.dumps(data), headers=headers) 269 | 270 | # if response.status_code == 200: 271 | # global blockchain 272 | # global peers 273 | # # update chain and the peers 274 | # chain_dump = response.json()['chain'] 275 | # blockchain = create_chain_from_dump(chain_dump) 276 | # peers.update(response.json()['peers']) 277 | # return "Registration successful", 200 278 | # else: 279 | # # if something goes wrong, pass it on to the API response 280 | # return response.content, response.status_code 281 | 282 | 283 | # def add_blocks(chain_dump): 284 | # # generated_blockchain = Blockchain() 285 | # # generated_blockchain.create_genesis_block() 286 | # for idx, block_data in enumerate(chain_dump): 287 | # if idx == 0: 288 | # continue # skip genesis block 289 | # block = Block(block_data["index"], 290 | # block_data["transactions"], 291 | # block_data["timestamp"], 292 | # block_data["previous_hash"], 293 | # block_data["nonce"]) 294 | # proof = block_data['hash'] 295 | # added = generated_blockchain.add_block(block, proof) 296 | # if not added: 297 | # raise Exception("The chain dump is tampered!!") 298 | # return generated_blockchain 299 | 300 | 301 | # endpoint to add a block mined by someone else to 302 | # the node's chain. The block is first verified by the node 303 | # and then added to the chain. 304 | # @app.route('/add_blocks', methods=['POST']) 305 | # def verify_and_add_blocks(blocks): 306 | # block_data = request.get_json() 307 | # block = Block(block_data["index"], 308 | # block_data["transactions"], 309 | # block_data["timestamp"], 310 | # block_data["previous_hash"], 311 | # block_data["nonce"]) 312 | 313 | # proof = block_data['hash'] 314 | # added = blockchain.add_block(block, proof) 315 | 316 | # if not added: 317 | # return "The block was discarded by the node", 400 318 | 319 | # return "Block added to the chain", 201 320 | 321 | 322 | # # endpoint to query unconfirmed transactions 323 | # @app.route('/pending_tx') 324 | # def get_pending_tx(): 325 | # return json.dumps(blockchain.unconfirmed_transactions) 326 | 327 | 328 | # def consensus(): 329 | # """ 330 | # Our naive consnsus algorithm. If a longer valid chain is 331 | # found, our chain is replaced with it. 332 | # """ 333 | # global blockchain 334 | 335 | # longest_chain = None 336 | # current_len = len(blockchain.chain) 337 | 338 | # for node in peers: 339 | # response = requests.get('{}chain'.format(node)) 340 | # length = response.json()['length'] 341 | # chain = response.json()['chain'] 342 | # if length > current_len and blockchain.check_chain_validity(chain): 343 | # current_len = length 344 | # longest_chain = chain 345 | 346 | # if longest_chain: 347 | # blockchain = longest_chain 348 | # return True 349 | 350 | # return False 351 | 352 | 353 | # def announce_new_block(block): 354 | # """ 355 | # A function to announce to the network once a block has been mined. 356 | # Other blocks can simply verify the proof of work and add it to their 357 | # respective chains. 358 | # """ 359 | # for peer in peers: 360 | # url = "{}add_block".format(peer) 361 | # headers = {'Content-Type': "application/json"} 362 | # requests.post(url, 363 | # data=json.dumps(block.__dict__, sort_keys=True), 364 | # headers=headers) 365 | 366 | # # Uncomment this line if you want to specify the port number in the code 367 | # #app.run(debug=True, port=8000) 368 | -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/client1.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import numpy 4 | import json 5 | 6 | import pygad 7 | import pygad.nn 8 | import pygad.gann 9 | import pandas 10 | import math 11 | import backprop as bp 12 | import blockchain as bl 13 | 14 | 15 | # Data Input 16 | 17 | df = pandas.read_csv('data.csv') 18 | 19 | data = df[:int(len(df)/2)] 20 | cli = "cli_1" 21 | 22 | X = data.drop('charges', axis=1) 23 | y = data['charges'] 24 | y = numpy.array(y) 25 | y = y.reshape((len(y), 1)) 26 | 27 | blockchain = bl.Blockchain() 28 | blockchain.create_genesis_block() 29 | # Preparing the NumPy array of the inputs. 30 | data_inputs = numpy.array(X) 31 | # print("Shape of input",data_inputs.shape) 32 | 33 | # Preparing the NumPy array of the outputs. 34 | data_outputs = numpy.array(y) 35 | 36 | data_inputs = data_inputs.T 37 | data_outputs = data_outputs.T 38 | 39 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 40 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 41 | data_inputs = (data_inputs - mean)/std_dev 42 | 43 | 44 | def recv(soc, buffer_size=1024, recv_timeout=10): 45 | received_data = b"" 46 | while str(received_data)[-18:-7] != '-----------': 47 | try: 48 | soc.settimeout(recv_timeout) 49 | received_data += soc.recv(buffer_size) 50 | except socket.timeout: 51 | print("A socket.timeout exception occurred because the server did not send any data for {recv_timeout} seconds.".format(recv_timeout=recv_timeout)) 52 | return None, 0 53 | except BaseException as e: 54 | return None, 0 55 | print("An error occurred while receiving data from the server {msg}.".format(msg=e)) 56 | 57 | try: 58 | # print(str(received_data)[-18:-7]) 59 | print("All data ({data_len} bytes).".format(data_len=len(received_data))) 60 | received_data = pickle.loads(received_data) 61 | except BaseException as e: 62 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 63 | return None, 0 64 | 65 | return received_data, 1 66 | 67 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 68 | print("Socket Created.\n") 69 | 70 | try: 71 | soc.connect(("localhost", 10000)) 72 | print("Successful Connection to the Server.\n") 73 | except BaseException as e: 74 | print("Error Connecting to the Server: {msg}".format(msg=e)) 75 | soc.close() 76 | print("Socket Closed.") 77 | 78 | subject = "echo" 79 | NN_model = None 80 | chain = None 81 | 82 | while True: 83 | data = {"subject": subject, "data": chain, "mark":"-----------"} 84 | data_byte = pickle.dumps(data) 85 | print("data sent to server {}".format(len(data_byte))) 86 | 87 | # for checking logs 88 | # f = open("logs.cli","a") 89 | # f.write(str(data_byte)) 90 | # f.close() 91 | print("Sending the Model to the Server.\n") 92 | soc.sendall(data_byte) 93 | 94 | print("Receiving Reply from the Server.") 95 | received_data, status = recv(soc=soc, 96 | buffer_size=1024, 97 | recv_timeout=10) 98 | if status == 0: 99 | print("Nothing Received from the Server.") 100 | break 101 | else: 102 | print(received_data, end="\n\n") 103 | 104 | subject = received_data["subject"] 105 | if subject == "model": 106 | # NN_model = received_data["data"] 107 | chain = received_data["data"] 108 | print("Length of chain", len(blockchain.chain)) 109 | last_block = blockchain.chain[-1] 110 | print("hash of last block client", last_block.hash) 111 | for k in chain: 112 | new_block = bl.Block(index=k.index, 113 | cli_model=k.cli_model, 114 | fin_model=k.fin_model, 115 | timestamp=k.timestamp, 116 | previous_hash=k.previous_hash, 117 | cli=k.cli, 118 | nonce=k.nonce) 119 | print("From ", k.cli) 120 | print("previous hash from server", k.previous_hash) 121 | proof = k.hash 122 | print("hash of this block", proof) 123 | blockchain = blockchain.add_block(new_block, proof) 124 | if not blockchain: 125 | raise Exception("The chain dump is tampered!!") 126 | # blockchain.add_blocks(chain) 127 | 128 | last_block = blockchain.chain[-1] 129 | # print(last_block.fin_model) 130 | NN_model = last_block.fin_model 131 | # print("Architecture of the model {}".format(NN_model.architecture)) 132 | # print("Cost function the model {}".format(NN_model.cost_function)) 133 | elif subject == "done": 134 | print("Model is trained.") 135 | break 136 | else: 137 | print("Unrecognized message type.") 138 | break 139 | 140 | # ga_instance = prepare_GA(GANN_instance) 141 | 142 | NN_model.data = data_inputs 143 | NN_model.labels = data_outputs 144 | 145 | history = NN_model.train(1000) 146 | # print(history) 147 | prediction = NN_model.layers[-1].a 148 | error = NN_model.calc_accuracy(data_inputs, data_outputs, "RMSE") 149 | 150 | # print("Predictions from model {predictions}".format(predictions = prediction)) 151 | print("Error from model(RMSE) {error}".format(error = error)) 152 | # ga_instance.run() 153 | 154 | # ga_instance.plot_result()s 155 | 156 | subject = "model" 157 | chain = bl.Block(last_block.index+1,NN_model, 0, 0, last_block.hash, cli) 158 | 159 | soc.close() 160 | print("Socket Closed.\n") -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/client2.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import numpy 4 | import json 5 | 6 | import pygad 7 | import pygad.nn 8 | import pygad.gann 9 | import pandas 10 | import math 11 | import backprop as bp 12 | import blockchain as bl 13 | 14 | 15 | # Data Input 16 | 17 | df = pandas.read_csv('data.csv') 18 | 19 | data = df[int(len(df)/2):] 20 | cli = "cli_2" 21 | 22 | X = data.drop('charges', axis=1) 23 | y = data['charges'] 24 | y = numpy.array(y) 25 | y = y.reshape((len(y), 1)) 26 | 27 | blockchain = bl.Blockchain() 28 | blockchain.create_genesis_block() 29 | # Preparing the NumPy array of the inputs. 30 | data_inputs = numpy.array(X) 31 | # print("Shape of input",data_inputs.shape) 32 | 33 | # Preparing the NumPy array of the outputs. 34 | data_outputs = numpy.array(y) 35 | 36 | data_inputs = data_inputs.T 37 | data_outputs = data_outputs.T 38 | 39 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 40 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 41 | data_inputs = (data_inputs - mean)/std_dev 42 | 43 | 44 | def recv(soc, buffer_size=1024, recv_timeout=10): 45 | received_data = b"" 46 | while str(received_data)[-18:-7] != '-----------': 47 | try: 48 | soc.settimeout(recv_timeout) 49 | received_data += soc.recv(buffer_size) 50 | except socket.timeout: 51 | print("A socket.timeout exception occurred because the server did not send any data for {recv_timeout} seconds.".format(recv_timeout=recv_timeout)) 52 | return None, 0 53 | except BaseException as e: 54 | return None, 0 55 | print("An error occurred while receiving data from the server {msg}.".format(msg=e)) 56 | 57 | try: 58 | # print(str(received_data)[-18:-7]) 59 | print("All data ({data_len} bytes).".format(data_len=len(received_data))) 60 | received_data = pickle.loads(received_data) 61 | except BaseException as e: 62 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 63 | return None, 0 64 | 65 | return received_data, 1 66 | 67 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 68 | print("Socket Created.\n") 69 | 70 | try: 71 | soc.connect(("localhost", 10000)) 72 | print("Successful Connection to the Server.\n") 73 | except BaseException as e: 74 | print("Error Connecting to the Server: {msg}".format(msg=e)) 75 | soc.close() 76 | print("Socket Closed.") 77 | 78 | subject = "echo" 79 | NN_model = None 80 | chain = None 81 | 82 | while True: 83 | data = {"subject": subject, "data": chain, "mark":"-----------"} 84 | data_byte = pickle.dumps(data) 85 | print("data sent to server {}".format(len(data_byte))) 86 | 87 | # for checking logs 88 | # f = open("logs.cli","a") 89 | # f.write(str(data_byte)) 90 | # f.close() 91 | print("Sending the Model to the Server.\n") 92 | soc.sendall(data_byte) 93 | 94 | print("Receiving Reply from the Server.") 95 | received_data, status = recv(soc=soc, 96 | buffer_size=1024, 97 | recv_timeout=10) 98 | if status == 0: 99 | print("Nothing Received from the Server.") 100 | break 101 | else: 102 | print(received_data, end="\n\n") 103 | 104 | subject = received_data["subject"] 105 | if subject == "model": 106 | # NN_model = received_data["data"] 107 | chain = received_data["data"] 108 | print("chain came") 109 | last_block = blockchain.chain[-1] 110 | print("hash of last block client", last_block.hash) 111 | for block in chain: 112 | new_block = bl.Block(index=block.index, 113 | cli_model=block.cli_model, 114 | fin_model=block.fin_model, 115 | timestamp=block.timestamp, 116 | previous_hash=block.previous_hash, 117 | cli=block.cli, 118 | nonce=block.nonce) 119 | print("From ", block.cli) 120 | print("previous hash from server", block.previous_hash) 121 | proof = block.hash 122 | print("hash of this block", proof) 123 | blockchain = blockchain.add_block(new_block, proof) 124 | if not blockchain: 125 | raise Exception("The chain dump is tampered!!") 126 | # blockchain.add_blocks(chain) 127 | 128 | last_block = blockchain.chain[-1] 129 | # print(last_block.fin_model) 130 | NN_model = last_block.fin_model 131 | # print("Architecture of the model {}".format(NN_model.architecture)) 132 | # print("Cost function the model {}".format(NN_model.cost_function)) 133 | elif subject == "done": 134 | print("Model is trained.") 135 | break 136 | else: 137 | print("Unrecognized message type.") 138 | break 139 | 140 | # ga_instance = prepare_GA(GANN_instance) 141 | 142 | NN_model.data = data_inputs 143 | NN_model.labels = data_outputs 144 | 145 | history = NN_model.train(1000) 146 | # print(history) 147 | prediction = NN_model.layers[-1].a 148 | error = NN_model.calc_accuracy(data_inputs, data_outputs, "RMSE") 149 | 150 | # print("Predictions from model {predictions}".format(predictions = prediction)) 151 | print("Error from model(RMSE) {error}".format(error = error)) 152 | # ga_instance.run() 153 | 154 | # ga_instance.plot_result() 155 | 156 | subject = "model" 157 | chain = bl.Block(last_block.index+1,NN_model, 0, 0, last_block.hash, cli) 158 | 159 | soc.close() 160 | print("Socket Closed.\n") -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import threading 4 | import time 5 | import json 6 | 7 | import pygad 8 | import pygad.nn 9 | import pygad.gann 10 | import numpy 11 | import pandas 12 | import backprop as bp 13 | import blockchain as bl 14 | 15 | model = None 16 | 17 | df = pandas.read_csv('data.csv') 18 | 19 | X = df.drop('charges', axis=1) 20 | y = df['charges'] 21 | 22 | y = numpy.array(y) 23 | y = y.reshape((len(y), 1)) 24 | 25 | blockchain = bl.Blockchain() 26 | blockchain.create_genesis_block() 27 | 28 | # Preparing the NumPy array of the inputs. 29 | data_inputs = numpy.array(X) 30 | # Preparing the NumPy array of the outputs. 31 | data_outputs = y 32 | 33 | data_inputs = data_inputs.T 34 | data_outputs = data_outputs.T 35 | 36 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 37 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 38 | data_inputs = (data_inputs - mean)/std_dev 39 | 40 | 41 | num_classes = 1 42 | num_inputs = 12 43 | sema = threading.Semaphore() 44 | 45 | # num_solutions = 6 46 | # GANN_instance = pygad.gann.GANN(num_solutions=num_solutions, 47 | # num_neurons_input=num_inputs, 48 | # num_neurons_hidden_layers=[12], 49 | # num_neurons_output=num_classes, 50 | # hidden_activations=["relu"], 51 | # output_activation="relu") 52 | 53 | description = [{"num_nodes" : 12, "activation" : "relu"}, 54 | {"num_nodes" : 1, "activation" : "relu"}] 55 | 56 | NN_model = bp.NeuralNetwork(description,num_inputs,"mean_squared", data_inputs, data_outputs, learning_rate=0.001) 57 | 58 | last_block = blockchain.chain[-1] 59 | new_block = bl.Block(index=last_block.index+1, 60 | cli_model=0, 61 | fin_model=NN_model, 62 | timestamp=time.time(), 63 | previous_hash=last_block.hash, 64 | cli="") 65 | proof = blockchain.proof_of_work(new_block) 66 | blockchain.add_block(new_block, proof) 67 | last_block = blockchain.chain[-1] 68 | counter = 2 69 | 70 | class SocketThread(threading.Thread): 71 | 72 | def __init__(self, connection, client_info, buffer_size=1024, recv_timeout=5): 73 | threading.Thread.__init__(self) 74 | self.connection = connection 75 | self.client_info = client_info 76 | self.buffer_size = buffer_size 77 | self.recv_timeout = recv_timeout 78 | # self.lock = threading.Lock() 79 | 80 | def recv(self): 81 | received_data = b"" 82 | while True: 83 | try: 84 | 85 | data = self.connection.recv(self.buffer_size) 86 | received_data += data 87 | 88 | if data == b'': # Nothing received from the client. 89 | received_data = b"" 90 | # If still nothing received for a number of seconds specified by the recv_timeout attribute, return with status 0 to close the connection. 91 | if (time.time() - self.recv_start_time) > self.recv_timeout: 92 | return None, 0 # 0 means the connection is no longer active and it should be closed. 93 | 94 | elif str(received_data)[-18:-7] == '-----------': 95 | # print(str(received_data)[-19:-8]) 96 | # print("All data ({data_len} bytes) Received from {client_info}.".format(client_info=self.client_info, data_len=len(received_data))) 97 | 98 | if len(received_data) > 0: 99 | try: 100 | # Decoding the data (bytes). 101 | received_data = pickle.loads(received_data) 102 | # Returning the decoded data. 103 | return received_data, 1 104 | 105 | except BaseException as e: 106 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 107 | return None, 0 108 | 109 | else: 110 | # In case data are received from the client, update the recv_start_time to the current time to reset the timeout counter. 111 | self.recv_start_time = time.time() 112 | 113 | except BaseException as e: 114 | print("Error Receiving Data from the Client: {msg}.\n".format(msg=e)) 115 | return None, 0 116 | 117 | def model_averaging(self, model, other_model): 118 | # print("Model ", model.layers) 119 | # print("Other_Model ",other_model.layers) 120 | for i in range(len(model.layers)): 121 | W_a = model.layers[i].W 122 | W_b = other_model.layers[i].W 123 | b_a = model.layers[i].b 124 | b_b = other_model.layers[i].b 125 | model.layers[i].W = (W_a + W_b)/2 126 | model.layers[i].b = (b_a + b_b)/2 127 | 128 | # print("Updated model", model.layers) 129 | 130 | return model 131 | 132 | 133 | # model_weights = numpy.array(model_weights) 134 | # other_model_weights = numpy.array(other_model_weights) 135 | # print("Shape of model",model_weights.shape) 136 | # new_weights = numpy.mean([model_weights, other_model_weights], axis=0) 137 | 138 | # pygad.nn.update_layers_trained_weights(last_layer=model, final_weights=new_weights) 139 | 140 | def reply(self, received_data): 141 | # self.lock.acquire() 142 | global NN_model, data_inputs, data_outputs, model, counter, blockchain 143 | if (type(received_data) is dict): 144 | if (("data" in received_data.keys()) and ("subject" in received_data.keys())): 145 | subject = received_data["subject"] 146 | # print("Client's Message Subject is {subject}.".format(subject=subject)) 147 | 148 | # print("Replying from Client.", received_data) 149 | if subject == "echo": 150 | chain = blockchain.chain[1:] 151 | if model is None: 152 | data = {"subject": "model", "data": chain, "mark": "-----------"} 153 | else: 154 | model.data = data_inputs 155 | model.labels = data_outputs 156 | model.forward_pass() 157 | 158 | predictions = model.layers[-1].a 159 | error = model.calc_accuracy(data_inputs, data_outputs, "RMSE") 160 | 161 | # error = numpy.sum(numpy.abs(predictions - data_outputs))/data_outputs.shape[0] 162 | # In case a client sent a model to the server despite that the model error is 0.0. In this case, no need to make changes in the model. 163 | if error <= 0.25: 164 | data = {"subject": "done", "data": chain, "mark": "-----------"} 165 | else: 166 | data = {"subject": "model", "data": chain, "mark": "-----------"} 167 | 168 | try: 169 | response = pickle.dumps(data) 170 | except BaseException as e: 171 | print("Error Encoding the Message: {msg}.\n".format(msg=e)) 172 | elif subject == "model": 173 | try: 174 | block_model = received_data["data"] 175 | reqd_index = block_model.index 176 | cli_model = block_model.cli_model 177 | cli = block_model.cli 178 | print("came from {}".format(cli)) 179 | 180 | # best_model_idx = received_data["best_solution_idx"] 181 | # print(GANN_instance, best_model_idx) 182 | # best_model = GANN_instance.population_networks[best_model_idx] 183 | if model is None: 184 | model = cli_model 185 | else: 186 | # print("shape of data {input}".format(input=data_inputs.shape)) 187 | model.data = data_inputs 188 | model.labels = data_outputs 189 | model.forward_pass() 190 | 191 | predictions = model.layers[-1].a 192 | 193 | # predictions = numpy.array(predictions) 194 | 195 | # predictions = predictions.reshape((-1,)) 196 | # print("predictions shape", predictions.shape) 197 | # print("data shape", data_outputs.shape) 198 | 199 | error = model.calc_accuracy(data_inputs, data_outputs, "RMSE") 200 | # In case a client sent a model to the server despite that the model error is 0.0. In this case, no need to make changes in the model. 201 | if error <= 0.25: 202 | chain = blockchain.chain[reqd_index:] 203 | data = {"subject": "done", "data": chain, "mark": "-----------"} 204 | response = pickle.dumps(data) 205 | # print("Error in total {}".format(error)) 206 | # return 207 | else: 208 | model_avg = self.model_averaging(model, cli_model) 209 | last_block = blockchain.chain[-1] 210 | new_block = bl.Block(index=last_block.index+1, 211 | cli_model=cli_model, 212 | fin_model=model_avg, 213 | timestamp=time.time(), 214 | previous_hash=last_block.hash, 215 | cli=cli) 216 | proof = blockchain.proof_of_work(new_block) 217 | blockchain.add_block(new_block, proof) 218 | model = model_avg 219 | counter+=1 220 | 221 | # print(best_model.trained_weights) 222 | # print(model.trained_weights) 223 | # print(model, best_model) 224 | # self.model_averaging(model, best_model) 225 | 226 | 227 | 228 | model.data = data_inputs 229 | model.labels = data_outputs 230 | model.forward_pass() 231 | 232 | predictions = model.layers[-1].a 233 | 234 | # predictions = numpy.array(predictions) 235 | # predictions = predictions.reshape((-1,)) 236 | # print("Model Predictions: {predictions}".format(predictions=predictions)) 237 | 238 | error = model.calc_accuracy(data_inputs, data_outputs, "MAE") 239 | print("Error(RMSE) from {info} = {error}".format(error=error, info=self.client_info)) 240 | print("counter ",counter) 241 | chain = blockchain.chain[reqd_index:] 242 | 243 | if error >= 0.25: 244 | data = {"subject": "model", "data": chain, "mark": "-----------"} 245 | response = pickle.dumps(data) 246 | else: 247 | data = {"subject": "done", "data": chain, "mark": "-----------"} 248 | response = pickle.dumps(data) 249 | 250 | except BaseException as e: 251 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 252 | else: 253 | response = pickle.dumps("Response from the Server") 254 | 255 | try: 256 | # print("Len of data sent {}".format(len(response))) 257 | self.connection.sendall(response) 258 | except BaseException as e: 259 | print("Error Sending Data to the Client: {msg}.\n".format(msg=e)) 260 | 261 | else: 262 | print("The received dictionary from the client must have the 'subject' and 'data' keys available. The existing keys are {d_keys}.".format(d_keys=received_data.keys())) 263 | else: 264 | print("A dictionary is expected to be received from the client but {d_type} received.".format(d_type=type(received_data))) 265 | # self.lock.release() 266 | 267 | def run(self): 268 | # print("Running a Thread for the Connection with {client_info}.".format(client_info=self.client_info)) 269 | 270 | # This while loop allows the server to wait for the client to send data more than once within the same connection. 271 | while True: 272 | self.recv_start_time = time.time() 273 | time_struct = time.gmtime() 274 | date_time = "Waiting to Receive Data Starting from {day}/{month}/{year} {hour}:{minute}:{second} GMT".format(year=time_struct.tm_year, month=time_struct.tm_mon, day=time_struct.tm_mday, hour=time_struct.tm_hour, minute=time_struct.tm_min, second=time_struct.tm_sec) 275 | print(date_time) 276 | received_data, status = self.recv() 277 | if status == 0: 278 | self.connection.close() 279 | print("Connection Closed with {client_info} either due to inactivity for {recv_timeout} seconds or due to an error.".format(client_info=self.client_info, recv_timeout=self.recv_timeout), end="\n\n") 280 | break 281 | 282 | # print(received_data) 283 | sema.acquire() 284 | self.reply(received_data) 285 | sema.release() 286 | 287 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 288 | print("Socket Created.\n") 289 | 290 | # Timeout after which the socket will be closed. 291 | # soc.settimeout(5) 292 | 293 | soc.bind(("localhost", 10000)) 294 | print("Socket Bound to IPv4 Address & Port Number.\n") 295 | 296 | soc.listen(1) 297 | print("Socket is Listening for Connections ....\n") 298 | 299 | all_data = b"" 300 | while True: 301 | try: 302 | connection, client_info = soc.accept() 303 | # print("New Connection from {client_info}.".format(client_info=client_info)) 304 | socket_thread = SocketThread(connection=connection, 305 | client_info=client_info, 306 | buffer_size=1024, 307 | recv_timeout=10) 308 | socket_thread.start() 309 | except: 310 | soc.close() 311 | print("(Timeout) Socket Closed Because no Connections Received.\n") 312 | break 313 | -------------------------------------------------------------------------------- /Federated (linear regression + blockchain)/stats.txt: -------------------------------------------------------------------------------- 1 | 2 | Model: "Linear Regression Model" 3 | Error with 1 agent 4 | client1 error(RMSE): 0.52 (half data) 5 | server error (RMSE): 0.6181 (full data) 6 | 7 | Error with 2 agents 8 | client1 error(RMSE): 0.52 (half data) 9 | client2 error(RMSE): 0.53 (other half) 10 | server error(RMSE): 0.6151 (full data) -------------------------------------------------------------------------------- /Federated (linear regression)/backprop.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Layer(): 4 | 5 | def __init__(self, model, f, d_f, input_dims = None, output_dims = None, input_layer=False, output_layer=False, learning_rate=0.001): 6 | 7 | self.model = model 8 | self.input_dims = input_dims 9 | self.output_dims = output_dims 10 | self.learning_rate = learning_rate 11 | 12 | # Parameters 13 | self.a = None 14 | self.z = None 15 | self.W = None 16 | self.b = None 17 | 18 | self.dW = None 19 | self.db = None 20 | self.da = None 21 | self.dz = None 22 | 23 | self.input_layer = input_layer 24 | self.output_layer = output_layer 25 | 26 | # Activation Functions 27 | self.f = f 28 | self.d_f = d_f 29 | 30 | # Adjacent layers set during backpropagation 31 | self.next_layer = None 32 | self.prev_layer = None 33 | 34 | 35 | def random_init(self): 36 | 37 | # Kaiming Weight Initialization 38 | self.W = np.random.randn(self.output_dims, self.input_dims)*np.sqrt(2)/np.sqrt(self.input_dims) 39 | 40 | # Xavier Weight Initialization 41 | self.b = np.zeros(shape=(self.output_dims, 1)) 42 | 43 | 44 | def get_prev_a(self): 45 | if self.input_layer: 46 | return self.model.data 47 | return self.prev_layer.a 48 | 49 | 50 | def forward_pass(self): 51 | prev_a = self.get_prev_a() 52 | self.z = self.W.dot(prev_a) + self.b 53 | self.a = self.f(self.z) 54 | 55 | 56 | def backpropagate(self): 57 | prev_a = self.get_prev_a() 58 | 59 | if self.output_layer: 60 | delta = self.model.calc_d_J(self.a) 61 | else: 62 | delta = self.next_layer.da 63 | 64 | m = prev_a.shape[1] 65 | 66 | self.dz = delta * self.d_f(self.z) 67 | self.dW = self.dz.dot(prev_a.T)/m 68 | self.db = np.sum(self.dz, axis=1, keepdims=True) 69 | self.da = self.W.T.dot(self.dz) 70 | 71 | def learn(self): 72 | self.W = self.W - self.learning_rate * self.dW 73 | self.b = self.b - self.learning_rate * self.db 74 | 75 | class NeuralNetwork(): 76 | 77 | def __init__(self, architecture, input_size, cost_function, train_data=None, train_labels=None, learning_rate=0.001): 78 | 79 | self.learning_rate = learning_rate 80 | self.architecture = architecture 81 | self.cost_function = cost_function 82 | 83 | # Create Layers 84 | self.layers = self.create_layers(architecture, input_size) 85 | 86 | # Cost Function 87 | self.J, self.d_J = cost_functions[cost_function] 88 | 89 | 90 | def calc_J(self, y_hat): 91 | return self.J(self.labels, y_hat) 92 | 93 | 94 | def calc_d_J(self, y_hat): 95 | return self.d_J(self.labels, y_hat) 96 | 97 | 98 | def calc_accuracy(self, test_data, test_labels, error_func="MSE"): 99 | self.data = test_data 100 | self.labels = test_labels 101 | 102 | # Forward Pass and get output 103 | self.forward_pass() 104 | y_hat = self.layers[-1].a 105 | 106 | if error_func == "MSE": 107 | return np.sum((self.labels - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2) 108 | elif error_func == "MAE": 109 | return np.sum(np.abs(y_hat-self.labels))/self.labels.shape[1] 110 | elif error_func == "RMSE": 111 | return np.sqrt(np.sum((self.labels - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2)) 112 | else: 113 | y_pred = np.where(y_hat > 0.5, 1, 0) 114 | return (y_pred == self.labels).mean() 115 | 116 | def create_layers(self, architecture, input_size): 117 | 118 | layers = [] 119 | 120 | for i, config in enumerate(architecture): 121 | input_dims = input_size if i == 0 else layers[-1].output_dims 122 | output_dims = config["num_nodes"] 123 | f, d_f = activation_functions[config["activation"]] 124 | layer = Layer(self, f, d_f, input_dims, output_dims, input_layer=(i==0), output_layer=(i==len(architecture)-1), learning_rate=self.learning_rate) 125 | 126 | if i != 0: 127 | layers[-1].next_layer = layer 128 | layer.prev_layer = layers[-1] 129 | 130 | 131 | layers.append(layer) 132 | 133 | for layer in layers: 134 | layer.random_init() 135 | 136 | return layers 137 | 138 | def add_data(self, train_data, train_labels): 139 | self.data = train_data 140 | self.labels = train_labels 141 | 142 | def forward_pass(self): 143 | for layer in self.layers: 144 | layer.forward_pass() 145 | 146 | def backward_pass(self): 147 | for layer in reversed(self.layers): 148 | layer.backpropagate() 149 | 150 | def learn(self): 151 | for layer in self.layers: 152 | layer.learn() 153 | 154 | def train(self, epochs): 155 | history = [] 156 | for i in range(epochs): 157 | self.forward_pass() 158 | cost = self.calc_J(self.layers[-1].a) 159 | history.append(cost) 160 | self.backward_pass() 161 | self.learn() 162 | 163 | # Training done. Return history 164 | return history 165 | 166 | # COST FUNCTIONS 167 | 168 | def cross_entropy_sigmoid(y, y_hat): 169 | m = y.shape[1] 170 | cost = (1./m) * (-np.dot(y,np.log(y_hat).T) - np.dot(1-y, np.log(1-y_hat).T)) 171 | cost = np.squeeze(cost) 172 | return cost 173 | 174 | 175 | def cross_entropy_sigmoid_derivative(y, y_hat): 176 | return (-(np.divide(y, y_hat) - np.divide(1 - y, 1 - y_hat))) 177 | 178 | 179 | def mean_squared(y, y_hat): 180 | return np.sum((y - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2) 181 | 182 | def d_mean_squared(y, y_hat): 183 | return (y_hat - y) 184 | 185 | 186 | cost_functions = {"cross_entropy_sigmoid" : (cross_entropy_sigmoid, cross_entropy_sigmoid_derivative), 187 | "mean_squared" : (mean_squared, d_mean_squared) 188 | } 189 | 190 | # ACTIVATION FUNCTIONS 191 | 192 | import numpy as np 193 | 194 | def sigmoid(x): 195 | s = 1/(1+np.exp(-x)) 196 | return s 197 | 198 | def d_sigmoid(x): 199 | s = sigmoid(x) 200 | return s*(1-s) 201 | 202 | def relu(x): 203 | return np.maximum(0,x) 204 | 205 | def d_relu(x): 206 | r = np.where(x > 0, 1, 0) 207 | return r 208 | 209 | def tanh(x): 210 | return np.tanh(x) 211 | 212 | def d_tanh(x): 213 | d = tanh(x) 214 | return 1 - d*d 215 | 216 | 217 | activation_functions = {"sigmoid" : (sigmoid, d_sigmoid) , "relu" : (relu, d_relu), "tanh" : (tanh, d_tanh)} -------------------------------------------------------------------------------- /Federated (linear regression)/client1.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import numpy 4 | 5 | import pygad 6 | import pygad.nn 7 | import pygad.gann 8 | import pandas 9 | import math 10 | import backprop as bp 11 | 12 | # Data Input 13 | df = pandas.read_csv('data.csv') 14 | 15 | data = df[:int(len(df)/2)] 16 | 17 | X = data.drop('charges', axis=1) 18 | y = data['charges'] 19 | y = numpy.array(y) 20 | y = y.reshape((len(y), 1)) 21 | 22 | 23 | # Preparing the NumPy array of the inputs. 24 | data_inputs = numpy.array(X) 25 | 26 | # Preparing the NumPy array of the outputs. 27 | data_outputs = numpy.array(y) 28 | 29 | data_inputs = data_inputs.T 30 | data_outputs = data_outputs.T 31 | 32 | # Normalizing data 33 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 34 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 35 | data_inputs = (data_inputs - mean)/std_dev 36 | 37 | 38 | def recv(soc, buffer_size=1024, recv_timeout=10): 39 | received_data = b"" 40 | while str(received_data)[-18:-7] != '-----------': 41 | try: 42 | soc.settimeout(recv_timeout) 43 | received_data += soc.recv(buffer_size) 44 | except socket.timeout: 45 | print("A socket.timeout exception occurred because the server did not send any data for {recv_timeout} seconds.".format(recv_timeout=recv_timeout)) 46 | return None, 0 47 | except BaseException as e: 48 | return None, 0 49 | print("An error occurred while receiving data from the server {msg}.".format(msg=e)) 50 | 51 | try: 52 | print("All data ({data_len} bytes).".format(data_len=len(received_data))) 53 | received_data = pickle.loads(received_data) 54 | except BaseException as e: 55 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 56 | return None, 0 57 | 58 | return received_data, 1 59 | 60 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 61 | print("Socket Created.\n") 62 | 63 | try: 64 | soc.connect(("localhost", 10000)) 65 | print("Successful Connection to the Server.\n") 66 | except BaseException as e: 67 | print("Error Connecting to the Server: {msg}".format(msg=e)) 68 | soc.close() 69 | print("Socket Closed.") 70 | 71 | subject = "echo" 72 | NN_model = None 73 | 74 | while True: 75 | data = {"subject": subject, "data": NN_model, "mark":"-----------"} 76 | data_byte = pickle.dumps(data) 77 | print("data sent to server {}".format(len(data_byte))) 78 | 79 | print("Sending the Model to the Server.\n") 80 | soc.sendall(data_byte) 81 | 82 | print("Receiving Reply from the Server.") 83 | received_data, status = recv(soc=soc, 84 | buffer_size=1024, 85 | recv_timeout=10) 86 | if status == 0: 87 | print("Nothing Received from the Server.") 88 | break 89 | else: 90 | print(received_data, end="\n\n") 91 | 92 | subject = received_data["subject"] 93 | if subject == "model": 94 | NN_model = received_data["data"] 95 | elif subject == "done": 96 | print("Model is trained.") 97 | break 98 | else: 99 | print("Unrecognized message type.") 100 | break 101 | 102 | # Data from Clients override 103 | NN_model.data = data_inputs 104 | NN_model.labels = data_outputs 105 | 106 | # Training the data 107 | history = NN_model.train(1000) 108 | prediction = NN_model.layers[-1].a 109 | error = NN_model.calc_accuracy(data_inputs, data_outputs, "RMSE") 110 | 111 | print("Predictions from model {predictions}".format(predictions = prediction)) 112 | print("Error from model(RMSE) {error}".format(error = error)) 113 | 114 | subject = "model" 115 | 116 | soc.close() 117 | print("Socket Closed.\n") -------------------------------------------------------------------------------- /Federated (linear regression)/client2.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import numpy 4 | 5 | import pygad 6 | import pygad.nn 7 | import pygad.gann 8 | import pandas 9 | import math 10 | import backprop as bp 11 | 12 | 13 | # Data Input 14 | df = pandas.read_csv('data.csv') 15 | 16 | data = df[int(len(df)/2):] 17 | 18 | X = data.drop('charges', axis=1) 19 | y = data['charges'] 20 | y = numpy.array(y) 21 | y = y.reshape((len(y), 1)) 22 | 23 | 24 | # Preparing the NumPy array of the inputs. 25 | data_inputs = numpy.array(X) 26 | # print("Shape of input",data_inputs.shape) 27 | 28 | # Preparing the NumPy array of the outputs. 29 | data_outputs = numpy.array(y) 30 | 31 | data_inputs = data_inputs.T 32 | data_outputs = data_outputs.T 33 | 34 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 35 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 36 | data_inputs = (data_inputs - mean)/std_dev 37 | 38 | 39 | def recv(soc, buffer_size=1024, recv_timeout=10): 40 | received_data = b"" 41 | while str(received_data)[-18:-7] != '-----------': 42 | try: 43 | soc.settimeout(recv_timeout) 44 | received_data += soc.recv(buffer_size) 45 | except socket.timeout: 46 | print("A socket.timeout exception occurred because the server did not send any data for {recv_timeout} seconds.".format(recv_timeout=recv_timeout)) 47 | return None, 0 48 | except BaseException as e: 49 | return None, 0 50 | print("An error occurred while receiving data from the server {msg}.".format(msg=e)) 51 | 52 | try: 53 | print("All data ({data_len} bytes).".format(data_len=len(received_data))) 54 | received_data = pickle.loads(received_data) 55 | except BaseException as e: 56 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 57 | return None, 0 58 | 59 | return received_data, 1 60 | 61 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 62 | print("Socket Created.\n") 63 | 64 | try: 65 | soc.connect(("localhost", 10000)) 66 | print("Successful Connection to the Server.\n") 67 | except BaseException as e: 68 | print("Error Connecting to the Server: {msg}".format(msg=e)) 69 | soc.close() 70 | print("Socket Closed.") 71 | 72 | subject = "echo" 73 | NN_model = None 74 | 75 | while True: 76 | data = {"subject": subject, "data": NN_model, "mark":"-----------"} 77 | data_byte = pickle.dumps(data) 78 | print("data sent to server {}".format(len(data_byte))) 79 | 80 | print("Sending the Model to the Server.\n") 81 | soc.sendall(data_byte) 82 | 83 | print("Receiving Reply from the Server.") 84 | received_data, status = recv(soc=soc, 85 | buffer_size=1024, 86 | recv_timeout=10) 87 | if status == 0: 88 | print("Nothing Received from the Server.") 89 | break 90 | else: 91 | print(received_data, end="\n\n") 92 | 93 | subject = received_data["subject"] 94 | if subject == "model": 95 | NN_model = received_data["data"] 96 | elif subject == "done": 97 | print("Model is trained.") 98 | break 99 | else: 100 | print("Unrecognized message type.") 101 | break 102 | 103 | NN_model.data = data_inputs 104 | NN_model.labels = data_outputs 105 | 106 | history = NN_model.train(1000) 107 | prediction = NN_model.layers[-1].a 108 | error = NN_model.calc_accuracy(data_inputs, data_outputs, "RMSE") 109 | 110 | print("Error from model(RMSE) {error}".format(error = error)) 111 | 112 | subject = "model" 113 | 114 | soc.close() 115 | print("Socket Closed.\n") -------------------------------------------------------------------------------- /Federated (linear regression)/server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import threading 4 | import time 5 | 6 | import pygad 7 | import pygad.nn 8 | import pygad.gann 9 | import numpy 10 | import pandas 11 | import backprop as bp 12 | 13 | model = None 14 | counter = 0 15 | 16 | df = pandas.read_csv('data.csv') 17 | 18 | X = df.drop('charges', axis=1) 19 | y = df['charges'] 20 | 21 | y = numpy.array(y) 22 | y = y.reshape((len(y), 1)) 23 | 24 | # Preparing the NumPy array of the inputs. 25 | data_inputs = numpy.array(X) 26 | # Preparing the NumPy array of the outputs. 27 | data_outputs = y 28 | 29 | data_inputs = data_inputs.T 30 | data_outputs = data_outputs.T 31 | 32 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 33 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 34 | data_inputs = (data_inputs - mean)/std_dev 35 | 36 | 37 | num_classes = 1 38 | num_inputs = 12 39 | sema = threading.Semaphore() 40 | 41 | description = [{"num_nodes" : 12, "activation" : "relu"}, 42 | {"num_nodes" : 1, "activation" : "relu"}] 43 | 44 | NN_model = bp.NeuralNetwork(description,num_inputs,"mean_squared", data_inputs, data_outputs, learning_rat=0.001) 45 | 46 | class SocketThread(threading.Thread): 47 | 48 | def __init__(self, connection, client_info, buffer_size=1024, recv_timeout=5): 49 | threading.Thread.__init__(self) 50 | self.connection = connection 51 | self.client_info = client_info 52 | self.buffer_size = buffer_size 53 | self.recv_timeout = recv_timeout 54 | 55 | def recv(self): 56 | received_data = b"" 57 | while True: 58 | try: 59 | 60 | data = self.connection.recv(self.buffer_size) 61 | received_data += data 62 | 63 | if data == b'': # Nothing received from the client. 64 | received_data = b"" 65 | # If still nothing received for a number of seconds specified by the recv_timeout attribute, return with status 0 to close the connection. 66 | if (time.time() - self.recv_start_time) > self.recv_timeout: 67 | return None, 0 # 0 means the connection is no longer active and it should be closed. 68 | 69 | elif str(received_data)[-18:-7] == '-----------': 70 | if len(received_data) > 0: 71 | try: 72 | # Decoding the data (bytes). 73 | received_data = pickle.loads(received_data) 74 | # Returning the decoded data. 75 | return received_data, 1 76 | 77 | except BaseException as e: 78 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 79 | return None, 0 80 | 81 | else: 82 | # In case data are received from the client, update the recv_start_time to the current time to reset the timeout counter. 83 | self.recv_start_time = time.time() 84 | 85 | except BaseException as e: 86 | print("Error Receiving Data from the Client: {msg}.\n".format(msg=e)) 87 | return None, 0 88 | 89 | def model_averaging(self, model, other_model): 90 | for i in range(len(model.layers)): 91 | W_a = model.layers[i].W 92 | W_b = other_model.layers[i].W 93 | b_a = model.layers[i].b 94 | b_b = other_model.layers[i].b 95 | model.layers[i].W = (W_a + W_b)/2 96 | model.layers[i].b = (b_a + b_b)/2 97 | 98 | return model 99 | 100 | def reply(self, received_data): 101 | global NN_model, data_inputs, data_outputs, model, counter 102 | if (type(received_data) is dict): 103 | if (("data" in received_data.keys()) and ("subject" in received_data.keys())): 104 | subject = received_data["subject"] 105 | 106 | if subject == "echo": 107 | if model is None: 108 | data = {"subject": "model", "data": NN_model, "mark": "-----------"} 109 | else: 110 | model.data = data_inputs 111 | model.labels = data_outputs 112 | model.forward_pass() 113 | 114 | predictions = model.layers[-1].a 115 | error = model.calc_accuracy(data_inputs, data_outputs, "RMSE") 116 | 117 | # In case a client sent a model to the server despite that the model error is 0.0. In this case, no need to make changes in the model. 118 | if error == 0: 119 | data = {"subject": "done", "data": model, "mark": "-----------"} 120 | else: 121 | data = {"subject": "model", "data": model, "mark": "-----------"} 122 | 123 | try: 124 | response = pickle.dumps(data) 125 | except BaseException as e: 126 | print("Error Encoding the Message: {msg}.\n".format(msg=e)) 127 | elif subject == "model": 128 | try: 129 | best_model = received_data["data"] 130 | if model is None: 131 | model = best_model 132 | print(model) 133 | else: 134 | model.data = data_inputs 135 | model.labels = data_outputs 136 | model.forward_pass() 137 | 138 | predictions = model.layers[-1].a 139 | 140 | error = model.calc_accuracy(data_inputs, data_outputs, "RMSE") 141 | # In case a client sent a model to the server despite that the model error is 0.0. In this case, no need to make changes in the model. 142 | if error <= 0.15: 143 | data = {"subject": "done", "data": None, "mark": "-----------"} 144 | response = pickle.dumps(data) 145 | else: 146 | model = self.model_averaging(model, best_model) 147 | 148 | model.data = data_inputs 149 | model.labels = data_outputs 150 | model.forward_pass() 151 | 152 | predictions = model.layers[-1].a 153 | 154 | error = model.calc_accuracy(data_inputs, data_outputs, "MAE") 155 | print("Error(RMSE) from {info} = {error}".format(error=error, info=self.client_info)) 156 | counter+=1 157 | print("counter: ",counter) 158 | if error >= 0.15: 159 | data = {"subject": "model", "data": model, "mark": "-----------"} 160 | print("sent", data) 161 | response = pickle.dumps(data) 162 | print("data_sent", len(response)) 163 | 164 | else: 165 | data = {"subject": "done", "data": None, "mark": "-----------"} 166 | response = pickle.dumps(data) 167 | 168 | except BaseException as e: 169 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 170 | else: 171 | response = pickle.dumps("Response from the Server") 172 | 173 | try: 174 | self.connection.sendall(response) 175 | except BaseException as e: 176 | print("Error Sending Data to the Client: {msg}.\n".format(msg=e)) 177 | 178 | else: 179 | print("The received dictionary from the client must have the 'subject' and 'data' keys available. The existing keys are {d_keys}.".format(d_keys=received_data.keys())) 180 | else: 181 | print("A dictionary is expected to be received from the client but {d_type} received.".format(d_type=type(received_data))) 182 | 183 | def run(self): 184 | 185 | # This while loop allows the server to wait for the client to send data more than once within the same connection. 186 | while True: 187 | self.recv_start_time = time.time() 188 | time_struct = time.gmtime() 189 | date_time = "Waiting to Receive Data Starting from {day}/{month}/{year} {hour}:{minute}:{second} GMT".format(year=time_struct.tm_year, month=time_struct.tm_mon, day=time_struct.tm_mday, hour=time_struct.tm_hour, minute=time_struct.tm_min, second=time_struct.tm_sec) 190 | print(date_time) 191 | # Client data 192 | received_data, status = self.recv() 193 | if status == 0: 194 | self.connection.close() 195 | print("Connection Closed with {client_info} either due to inactivity for {recv_timeout} seconds or due to an error.".format(client_info=self.client_info, recv_timeout=self.recv_timeout), end="\n\n") 196 | break 197 | 198 | sema.acquire() 199 | self.reply(received_data) 200 | sema.release() 201 | 202 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 203 | print("Socket Created.\n") 204 | 205 | soc.bind(("localhost", 10000)) 206 | print("Socket Bound to IPv4 Address & Port Number.\n") 207 | 208 | soc.listen(1) 209 | print("Socket is Listening for Connections ....\n") 210 | 211 | all_data = b"" 212 | while True: 213 | try: 214 | connection, client_info = soc.accept() 215 | socket_thread = SocketThread(connection=connection, 216 | client_info=client_info, 217 | buffer_size=1024, 218 | recv_timeout=10) 219 | socket_thread.start() 220 | except: 221 | soc.close() 222 | print("(Timeout) Socket Closed Because no Connections Received.\n") 223 | break 224 | -------------------------------------------------------------------------------- /Federated (linear regression)/statistics.txt: -------------------------------------------------------------------------------- 1 | Model: "Linear Regression Model" 2 | Error with 1 agent 3 | client1 error(RMSE): 0.52 (half data) 4 | server error (RMSE): 0.6181 (full data) 5 | 6 | Error with 2 agents 7 | client1 error(RMSE): 0.52 (half data) 8 | client2 error(RMSE): 0.53 (other half) 9 | server error(RMSE): 0.6151 (full data) -------------------------------------------------------------------------------- /Need for Blockchain/__pycache__/backprop.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repeatedd/federated-learning-blockchain/57fc408ebb990130d128e05df63538669e1f8b0f/Need for Blockchain/__pycache__/backprop.cpython-38.pyc -------------------------------------------------------------------------------- /Need for Blockchain/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repeatedd/federated-learning-blockchain/57fc408ebb990130d128e05df63538669e1f8b0f/Need for Blockchain/a.out -------------------------------------------------------------------------------- /Need for Blockchain/backprop.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | # from tqdm._tqdm_notebook import tqdm_notebook as tqdm 3 | # tqdm().pandas() 4 | 5 | class Layer(): 6 | 7 | def __init__(self, model, f, d_f, input_dims = None, output_dims = None, input_layer=False, output_layer=False, learning_rate=0.001): 8 | 9 | self.model = model 10 | self.input_dims = input_dims 11 | self.output_dims = output_dims 12 | self.learning_rate = learning_rate 13 | 14 | # Parameters 15 | self.a = None 16 | self.z = None 17 | self.W = None 18 | self.b = None 19 | 20 | self.dW = None 21 | self.db = None 22 | self.da = None 23 | self.dz = None 24 | 25 | self.input_layer = input_layer 26 | self.output_layer = output_layer 27 | 28 | # Activation Functions 29 | self.f = f 30 | self.d_f = d_f 31 | 32 | # Adjacent layers set during backpropagation 33 | self.next_layer = None 34 | self.prev_layer = None 35 | 36 | 37 | def random_init(self): 38 | 39 | # Kaiming Weight Initialization 40 | self.W = np.random.randn(self.output_dims, self.input_dims)*np.sqrt(2)/np.sqrt(self.input_dims) 41 | 42 | # Xavier Weight Initialization 43 | # B = np.sqrt(6)/np.sqrt(self.input_dims + self.output_dims) 44 | # self.W = np.random.uniform(low=-B , high=B ,size=(self.output_dims, self.input_dims)) 45 | 46 | self.b = np.zeros(shape=(self.output_dims, 1)) 47 | 48 | 49 | def get_prev_a(self): 50 | if self.input_layer: 51 | return self.model.data 52 | return self.prev_layer.a 53 | 54 | 55 | def forward_pass(self): 56 | prev_a = self.get_prev_a() 57 | self.z = self.W.dot(prev_a) + self.b 58 | self.a = self.f(self.z) 59 | 60 | 61 | def backpropagate(self): 62 | prev_a = self.get_prev_a() 63 | 64 | if self.output_layer: 65 | delta = self.model.calc_d_J(self.a) 66 | else: 67 | delta = self.next_layer.da 68 | 69 | m = prev_a.shape[1] 70 | 71 | self.dz = delta * self.d_f(self.z) 72 | self.dW = self.dz.dot(prev_a.T)/m 73 | self.db = np.sum(self.dz, axis=1, keepdims=True) 74 | self.da = self.W.T.dot(self.dz) 75 | 76 | def learn(self): 77 | self.W = self.W - self.learning_rate * self.dW 78 | self.b = self.b - self.learning_rate * self.db 79 | 80 | class NeuralNetwork(): 81 | 82 | def __init__(self, architecture, input_size, cost_function, train_data=None, train_labels=None, learning_rate=0.001): 83 | 84 | self.learning_rate = learning_rate 85 | self.architecture = architecture 86 | self.cost_function = cost_function 87 | 88 | # Create Layers 89 | self.layers = self.create_layers(architecture, input_size) 90 | 91 | # Data 92 | # self.data = train_data 93 | # self.labels = train_labels 94 | 95 | # Cost Function 96 | self.J, self.d_J = cost_functions[cost_function] 97 | 98 | 99 | def calc_J(self, y_hat): 100 | return self.J(self.labels, y_hat) 101 | 102 | 103 | def calc_d_J(self, y_hat): 104 | return self.d_J(self.labels, y_hat) 105 | 106 | 107 | def calc_accuracy(self, test_data, test_labels, error_func="MSE"): 108 | self.data = test_data 109 | self.labels = test_labels 110 | 111 | # Forward Pass and get output 112 | self.forward_pass() 113 | y_hat = self.layers[-1].a 114 | 115 | if error_func == "MSE": 116 | # return np.sqrt(np.sum(y_hat-self.labels))/self.labels.shape[1] 117 | return np.sum((self.labels - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2) 118 | elif error_func == "MAE": 119 | return np.sum(np.abs(y_hat-self.labels))/self.labels.shape[1] 120 | elif error_func == "RMSE": 121 | return np.sqrt(np.sum((self.labels - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2)) 122 | else: 123 | y_pred = np.where(y_hat > 0.5, 1, 0) 124 | return (y_pred == self.labels).mean() 125 | 126 | def create_layers(self, architecture, input_size): 127 | 128 | layers = [] 129 | 130 | for i, config in enumerate(architecture): 131 | input_dims = input_size if i == 0 else layers[-1].output_dims 132 | output_dims = config["num_nodes"] 133 | f, d_f = activation_functions[config["activation"]] 134 | layer = Layer(self, f, d_f, input_dims, output_dims, input_layer=(i==0), output_layer=(i==len(architecture)-1), learning_rate=self.learning_rate) 135 | 136 | if i != 0: 137 | layers[-1].next_layer = layer 138 | layer.prev_layer = layers[-1] 139 | 140 | 141 | layers.append(layer) 142 | 143 | for layer in layers: 144 | layer.random_init() 145 | 146 | return layers 147 | 148 | def add_data(self, train_data, train_labels): 149 | self.data = train_data 150 | self.labels = train_labels 151 | 152 | def forward_pass(self): 153 | for layer in self.layers: 154 | layer.forward_pass() 155 | 156 | def backward_pass(self): 157 | for layer in reversed(self.layers): 158 | layer.backpropagate() 159 | 160 | def learn(self): 161 | for layer in self.layers: 162 | layer.learn() 163 | 164 | def train(self, epochs): 165 | history = [] 166 | for i in range(epochs): 167 | self.forward_pass() 168 | cost = self.calc_J(self.layers[-1].a) 169 | history.append(cost) 170 | # if i % 50 == 0: 171 | # print ("Cost after iteration %i: %f" %(i, cost)) 172 | self.backward_pass() 173 | self.learn() 174 | 175 | # Training done. Return history 176 | return history 177 | 178 | # COST FUNCTIONS 179 | 180 | def cross_entropy_sigmoid(y, y_hat): 181 | m = y.shape[1] 182 | cost = (1./m) * (-np.dot(y,np.log(y_hat).T) - np.dot(1-y, np.log(1-y_hat).T)) 183 | cost = np.squeeze(cost) 184 | return cost 185 | 186 | 187 | def cross_entropy_sigmoid_derivative(y, y_hat): 188 | return (-(np.divide(y, y_hat) - np.divide(1 - y, 1 - y_hat))) 189 | 190 | 191 | def mean_squared(y, y_hat): 192 | return np.sum((y - y_hat)**2 ).squeeze() / (y_hat.shape[1]*2) 193 | 194 | def d_mean_squared(y, y_hat): 195 | return (y_hat - y) 196 | 197 | 198 | cost_functions = {"cross_entropy_sigmoid" : (cross_entropy_sigmoid, cross_entropy_sigmoid_derivative), 199 | "mean_squared" : (mean_squared, d_mean_squared) 200 | } 201 | 202 | # ACTIVATION FUNCTIONS 203 | 204 | import numpy as np 205 | 206 | def sigmoid(x): 207 | s = 1/(1+np.exp(-x)) 208 | return s 209 | 210 | def d_sigmoid(x): 211 | s = sigmoid(x) 212 | return s*(1-s) 213 | 214 | def relu(x): 215 | return np.maximum(0,x) 216 | 217 | def d_relu(x): 218 | r = np.where(x > 0, 1, 0) 219 | return r 220 | 221 | def tanh(x): 222 | return np.tanh(x) 223 | 224 | def d_tanh(x): 225 | d = tanh(x) 226 | return 1 - d*d 227 | 228 | 229 | activation_functions = {"sigmoid" : (sigmoid, d_sigmoid) , "relu" : (relu, d_relu), "tanh" : (tanh, d_tanh)} 230 | 231 | """# Application on Cancer Dataset""" 232 | 233 | # import matplotlib.pyplot as plt 234 | # from sklearn.model_selection import train_test_split 235 | # from sklearn.datasets import load_breast_cancer 236 | 237 | # X, y = load_breast_cancer(return_X_y=True) 238 | # y = y.reshape((len(y), 1)) 239 | 240 | # # Split Data 241 | # train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2) 242 | # train_X = train_X.T 243 | # test_X = test_X.T 244 | 245 | # # Normalize 246 | # mean = np.mean(train_X, axis = 1, keepdims=True) 247 | # std_dev = np.std(train_X, axis = 1, keepdims=True) 248 | # train_X = (train_X - mean)/std_dev 249 | # test_X = (test_X - mean)/std_dev 250 | 251 | # train_y = train_y.T 252 | # test_y = test_y.T 253 | 254 | # train_X.shape, train_y.shape, test_X.shape, test_y.shape 255 | 256 | # description = [{"num_nodes" : 100, "activation" : "relu"}, 257 | # {"num_nodes" : 50, "activation" : "relu"}, 258 | # {"num_nodes" : 1, "activation" : "sigmoid"}] 259 | 260 | # model = NeuralNetwork(description,30,"cross_entropy_sigmoid", train_X, train_y, learning_rate=0.001) 261 | 262 | # history = model.train(1000) 263 | 264 | # plt.plot(history) 265 | 266 | # acc = model.calc_accuracy(train_X, train_y) 267 | # print("Accuracy of the model on the training set is = {}".format(acc)) 268 | 269 | # acc = model.calc_accuracy(test_X, test_y) 270 | # print("Accuracy of the model on the test set is = {}".format(acc)) 271 | 272 | -------------------------------------------------------------------------------- /Need for Blockchain/backprop.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repeatedd/federated-learning-blockchain/57fc408ebb990130d128e05df63538669e1f8b0f/Need for Blockchain/backprop.pyc -------------------------------------------------------------------------------- /Need for Blockchain/backprop_modified.py: -------------------------------------------------------------------------------- 1 | import backprop as bp 2 | import numpy as np 3 | import pandas as pd 4 | import matplotlib.pyplot as plt 5 | from sklearn.model_selection import train_test_split 6 | from sklearn.datasets import load_breast_cancer 7 | 8 | 9 | df = pd.read_csv('data.csv') 10 | 11 | X = np.array(df.drop('charges', axis=1)) 12 | y = np.array(df['charges']) 13 | # X, y = load_breast_cancer(return_X_y=True) 14 | y = y.reshape((len(y), 1)) 15 | print(X.shape) 16 | 17 | # Split Data 18 | train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2) 19 | train_X = train_X.T 20 | test_X = test_X.T 21 | 22 | print(train_X.shape) 23 | # Normalize 24 | mean = np.mean(train_X, axis = 1, keepdims=True) 25 | std_dev = np.std(train_X, axis = 1, keepdims=True) 26 | train_X = (train_X - mean)/std_dev 27 | test_X = (test_X - mean)/std_dev 28 | 29 | train_y = train_y.T 30 | test_y = test_y.T 31 | 32 | train_X.shape, train_y.shape, test_X.shape, test_y.shape 33 | 34 | description = [{"num_nodes" : 12, "activation" : "relu"}, 35 | # {"num_nodes" : 12, "activation" : "relu"}, 36 | {"num_nodes" : 1, "activation" : "relu"}] 37 | 38 | model = bp.NeuralNetwork(description,12,"mean_squared", train_X, train_y, learning_rate=0.001) 39 | 40 | for i in range(len(model.layers)): 41 | print(model.layers[i].W) 42 | print(model.layers[i].b) 43 | 44 | history = model.train(2000) 45 | 46 | plt.plot(history) 47 | 48 | acc = model.calc_accuracy(train_X, train_y, "RMSE") 49 | print("MSE on the training set is = {}".format(acc)) 50 | 51 | acc = model.calc_accuracy(test_X, test_y,"RMSE") 52 | print("MSE on the test set is = {}".format(acc)) 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Need for Blockchain/client1.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import numpy 4 | 5 | import pygad 6 | import pygad.nn 7 | import pygad.gann 8 | import pandas 9 | import math 10 | import backprop as bp 11 | 12 | 13 | # Data Input 14 | 15 | df = pandas.read_csv('data.csv') 16 | 17 | data = df[:int(len(df)/2)] 18 | 19 | X = data.drop('charges', axis=1) 20 | y = data['charges'] 21 | y = numpy.array(y) 22 | y = y.reshape((len(y), 1)) 23 | 24 | 25 | # Preparing the NumPy array of the inputs. 26 | data_inputs = numpy.array(X) 27 | # print("Shape of input",data_inputs.shape) 28 | 29 | # Preparing the NumPy array of the outputs. 30 | data_outputs = numpy.array(y) 31 | 32 | data_inputs = data_inputs.T 33 | data_outputs = data_outputs.T 34 | 35 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 36 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 37 | data_inputs = (data_inputs - mean)/std_dev 38 | 39 | 40 | def recv(soc, buffer_size=1024, recv_timeout=10): 41 | received_data = b"" 42 | while str(received_data)[-18:-7] != '-----------': 43 | try: 44 | soc.settimeout(recv_timeout) 45 | received_data += soc.recv(buffer_size) 46 | except socket.timeout: 47 | print("A socket.timeout exception occurred because the server did not send any data for {recv_timeout} seconds.".format(recv_timeout=recv_timeout)) 48 | return None, 0 49 | except BaseException as e: 50 | return None, 0 51 | print("An error occurred while receiving data from the server {msg}.".format(msg=e)) 52 | 53 | try: 54 | # print(str(received_data)[-18:-7]) 55 | print("All data ({data_len} bytes).".format(data_len=len(received_data))) 56 | received_data = pickle.loads(received_data) 57 | except BaseException as e: 58 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 59 | return None, 0 60 | 61 | return received_data, 1 62 | 63 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 64 | print("Socket Created.\n") 65 | 66 | try: 67 | soc.connect(("localhost", 10000)) 68 | print("Successful Connection to the Server.\n") 69 | except BaseException as e: 70 | print("Error Connecting to the Server: {msg}".format(msg=e)) 71 | soc.close() 72 | print("Socket Closed.") 73 | 74 | subject = "echo" 75 | NN_model = None 76 | 77 | while True: 78 | data = {"subject": subject, "data": NN_model, "mark":"-----------"} 79 | data_byte = pickle.dumps(data) 80 | print("data sent to server {}".format(len(data_byte))) 81 | 82 | # for checking logs 83 | # f = open("logs.cli","a") 84 | # f.write(str(data_byte)) 85 | # f.close() 86 | print("Sending the Model to the Server.\n") 87 | soc.sendall(data_byte) 88 | 89 | print("Receiving Reply from the Server.") 90 | received_data, status = recv(soc=soc, 91 | buffer_size=1024, 92 | recv_timeout=10) 93 | if status == 0: 94 | print("Nothing Received from the Server.") 95 | break 96 | else: 97 | print(received_data, end="\n\n") 98 | 99 | subject = received_data["subject"] 100 | if subject == "model": 101 | NN_model = received_data["data"] 102 | print(NN_model) 103 | f = open("model_logs", "a") 104 | # f.write(str(NN_model.tolist())) 105 | # f.write("-------------------") 106 | # f.close() 107 | # print("Architecture of the model {}".format(NN_model.architecture)) 108 | # print("Cost function the model {}".format(NN_model.cost_function)) 109 | elif subject == "done": 110 | print("Model is trained.") 111 | break 112 | else: 113 | print("Unrecognized message type.") 114 | break 115 | 116 | # ga_instance = prepare_GA(GANN_instance) 117 | 118 | NN_model.data = data_inputs 119 | NN_model.labels = data_outputs 120 | NN_model.forward_pass() 121 | print("Error of server model", NN_model.calc_accuracy(data_inputs, data_outputs, "RMSE")) 122 | 123 | 124 | history = NN_model.train(1000) 125 | # print(history) 126 | prediction = NN_model.layers[-1].a 127 | error = NN_model.calc_accuracy(data_inputs, data_outputs, "RMSE") 128 | 129 | # print("Predictions from model {predictions}".format(predictions = prediction)) 130 | print("Error after training(RMSE) {error}".format(error = error)) 131 | # ga_instance.run() 132 | 133 | # ga_instance.plot_result()s 134 | 135 | subject = "model" 136 | 137 | soc.close() 138 | print("Socket Closed.\n") -------------------------------------------------------------------------------- /Need for Blockchain/client2.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import numpy 4 | 5 | import pygad 6 | import pygad.nn 7 | import pygad.gann 8 | import pandas 9 | import math 10 | import backprop as bp 11 | 12 | 13 | # Data Input 14 | 15 | df = pandas.read_csv('data.csv') 16 | 17 | data = df[int(len(df)/2):] 18 | 19 | X = data.drop('charges', axis=1) 20 | y = data['charges'] 21 | y = numpy.array(y) 22 | y = y.reshape((len(y), 1)) 23 | 24 | 25 | # Preparing the NumPy array of the inputs. 26 | data_inputs = numpy.array(X) 27 | # print("Shape of input",data_inputs.shape) 28 | 29 | # Preparing the NumPy array of the outputs. 30 | data_outputs = numpy.array(y) 31 | 32 | data_inputs = data_inputs.T 33 | data_outputs = data_outputs.T 34 | 35 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 36 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 37 | data_inputs = (data_inputs - mean)/std_dev 38 | 39 | 40 | def recv(soc, buffer_size=1024, recv_timeout=10): 41 | received_data = b"" 42 | while str(received_data)[-18:-7] != '-----------': 43 | try: 44 | soc.settimeout(recv_timeout) 45 | received_data += soc.recv(buffer_size) 46 | except socket.timeout: 47 | print("A socket.timeout exception occurred because the server did not send any data for {recv_timeout} seconds.".format(recv_timeout=recv_timeout)) 48 | return None, 0 49 | except BaseException as e: 50 | return None, 0 51 | print("An error occurred while receiving data from the server {msg}.".format(msg=e)) 52 | 53 | try: 54 | # print(str(received_data)[-18:-7]) 55 | print("All data ({data_len} bytes).".format(data_len=len(received_data))) 56 | received_data = pickle.loads(received_data) 57 | except BaseException as e: 58 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 59 | return None, 0 60 | 61 | return received_data, 1 62 | 63 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 64 | print("Socket Created.\n") 65 | 66 | try: 67 | soc.connect(("localhost", 10000)) 68 | print("Successful Connection to the Server.\n") 69 | except BaseException as e: 70 | print("Error Connecting to the Server: {msg}".format(msg=e)) 71 | soc.close() 72 | print("Socket Closed.") 73 | 74 | subject = "echo" 75 | NN_model = None 76 | 77 | while True: 78 | data = {"subject": subject, "data": NN_model, "mark":"-----------"} 79 | data_byte = pickle.dumps(data) 80 | print("data sent to server {}".format(len(data_byte))) 81 | 82 | # for checking logs 83 | # f = open("logs.cli","a") 84 | # f.write(str(data_byte)) 85 | # f.close() 86 | print("Sending the Model to the Server.\n") 87 | soc.sendall(data_byte) 88 | 89 | print("Receiving Reply from the Server.") 90 | received_data, status = recv(soc=soc, 91 | buffer_size=1024, 92 | recv_timeout=10) 93 | if status == 0: 94 | print("Nothing Received from the Server.") 95 | break 96 | else: 97 | print(received_data, end="\n\n") 98 | 99 | subject = received_data["subject"] 100 | if subject == "model": 101 | NN_model = received_data["data"] 102 | # print("Architecture of the model {}".format(NN_model.architecture)) 103 | # print("Cost function the model {}".format(NN_model.cost_function)) 104 | elif subject == "done": 105 | print("Model is trained.") 106 | break 107 | else: 108 | print("Unrecognized message type.") 109 | break 110 | 111 | # ga_instance = prepare_GA(GANN_instance) 112 | 113 | NN_model.data = data_inputs 114 | NN_model.labels = data_outputs 115 | NN_model.forward_pass() 116 | 117 | print("Error from server model ", NN_model.calc_accuracy(data_inputs, data_outputs, "RMSE")) 118 | 119 | 120 | 121 | history = NN_model.train(1000) 122 | # print(history) 123 | prediction = NN_model.layers[-1].a 124 | error = NN_model.calc_accuracy(data_inputs, data_outputs, "RMSE") 125 | 126 | # print("Predictions from model {predictions}".format(predictions = prediction)) 127 | print("Error after training(RMSE) {error}".format(error = error)) 128 | # ga_instance.run() 129 | 130 | # ga_instance.plot_result() 131 | 132 | subject = "model" 133 | 134 | soc.close() 135 | print("Socket Closed.\n") -------------------------------------------------------------------------------- /Need for Blockchain/data.csv: -------------------------------------------------------------------------------- 1 | age,bmi,charges,OHE_male,OHE_1,OHE_2,OHE_3,OHE_4,OHE_5,OHE_yes,OHE_northwest,OHE_southeast,OHE_southwest 2 | 19,27.9,9.734176431773115,0,0,0,0,0,0,1,0,0,1 3 | 18,33.77,7.453302452133774,1,1,0,0,0,0,0,0,1,0 4 | 28,33.0,8.400538468975023,1,0,0,1,0,0,0,0,1,0 5 | 33,22.705,9.998091601725266,1,0,0,0,0,0,0,1,0,0 6 | 32,28.88,8.260196845858372,1,0,0,0,0,0,0,1,0,0 7 | 31,25.74,8.231275321843,0,0,0,0,0,0,0,0,1,0 8 | 46,33.44,9.016827173741753,0,1,0,0,0,0,0,0,1,0 9 | 37,27.74,8.893092932994646,0,0,0,1,0,0,0,1,0,0 10 | 37,29.83,8.765054439884247,1,0,1,0,0,0,0,0,0,0 11 | 60,25.84,10.272397139270046,0,0,0,0,0,0,0,1,0,0 12 | 25,26.22,7.908872629665523,1,0,0,0,0,0,0,0,0,0 13 | 62,26.29,10.233105102955316,0,0,0,0,0,0,1,0,1,0 14 | 23,34.4,7.510344619461671,1,0,0,0,0,0,0,0,0,1 15 | 56,39.82,9.3138638032273,0,0,0,0,0,0,0,0,1,0 16 | 27,42.13,10.586881264789202,1,0,0,0,0,0,1,0,1,0 17 | 19,24.6,7.516018091591322,1,1,0,0,0,0,0,0,0,1 18 | 52,30.78,9.287054734541506,0,1,0,0,0,0,0,0,0,0 19 | 23,23.845,7.78121013567231,1,0,0,0,0,0,0,0,0,0 20 | 56,40.3,9.268834254791456,1,0,0,0,0,0,0,0,0,1 21 | 30,35.3,10.514270731219286,1,0,0,0,0,0,1,0,0,1 22 | 60,36.005,9.490155099115842,0,0,0,0,0,0,0,0,0,0 23 | 30,32.4,8.330799996743426,0,1,0,0,0,0,0,0,0,1 24 | 18,34.1,7.036158168285971,1,0,0,0,0,0,0,0,1,0 25 | 34,31.92,10.537465154690363,0,1,0,0,0,0,1,0,0,0 26 | 37,28.025,8.73293368761397,1,0,1,0,0,0,0,1,0,0 27 | 59,27.72,9.546893591032516,0,0,0,1,0,0,0,0,1,0 28 | 63,23.085,9.578576685476762,0,0,0,0,0,0,0,0,0,0 29 | 55,32.775,9.414801060423951,0,0,1,0,0,0,0,1,0,0 30 | 23,17.385,7.928475267026576,1,1,0,0,0,0,0,1,0,0 31 | 31,36.3,10.563879076356082,1,0,1,0,0,0,1,0,0,1 32 | 22,35.6,10.479695666197845,1,0,0,0,0,0,1,0,0,1 33 | 18,26.315,7.695389505209892,0,0,0,0,0,0,0,0,0,0 34 | 19,28.6,8.452718028271507,0,0,0,0,0,1,0,0,0,1 35 | 63,28.31,9.530254701356105,1,0,0,0,0,0,0,1,0,0 36 | 28,36.4,10.843388538584009,1,1,0,0,0,0,1,0,0,1 37 | 19,20.425,7.393529982223134,1,0,0,0,0,0,0,1,0,0 38 | 62,32.965,9.65580751292789,0,0,0,1,0,0,0,1,0,0 39 | 26,20.8,7.741663902250325,1,0,0,0,0,0,0,0,0,1 40 | 35,36.67,10.59097565819445,1,1,0,0,0,0,1,0,0,0 41 | 60,39.9,10.782561470908275,1,0,0,0,0,0,1,0,0,1 42 | 24,26.6,8.021604887811318,0,0,0,0,0,0,0,0,0,0 43 | 31,36.63,8.507094106899793,0,0,1,0,0,0,0,0,1,0 44 | 41,21.78,8.743926643319663,1,1,0,0,0,0,0,0,1,0 45 | 37,30.8,8.750486499241552,0,0,1,0,0,0,0,0,1,0 46 | 38,37.05,8.712705943895298,1,1,0,0,0,0,0,0,0,0 47 | 55,37.3,9.93451534857872,1,0,0,0,0,0,0,0,0,1 48 | 18,38.665,8.129574784321063,0,0,1,0,0,0,0,0,0,0 49 | 28,34.77,8.176650927459093,0,0,0,0,0,0,0,1,0,0 50 | 60,24.53,9.443822036372055,0,0,0,0,0,0,0,0,1,0 51 | 36,35.2,10.563831956855854,1,1,0,0,0,0,1,0,1,0 52 | 18,35.625,7.701259315246468,0,0,0,0,0,0,0,0,0,0 53 | 21,33.63,8.183070229087928,0,0,1,0,0,0,0,1,0,0 54 | 48,28.0,10.067656679708454,1,1,0,0,0,0,1,0,0,1 55 | 36,34.43,10.538544065136376,1,0,0,0,0,0,1,0,1,0 56 | 40,28.69,8.994629020812297,0,0,0,1,0,0,0,1,0,0 57 | 58,36.955,10.76841118624667,1,0,1,0,0,0,1,1,0,0 58 | 58,31.825,9.518366744845707,0,0,1,0,0,0,0,0,0,0 59 | 18,31.68,10.442992967083542,1,0,1,0,0,0,1,0,1,0 60 | 53,22.88,10.053836308487051,0,1,0,0,0,0,1,0,1,0 61 | 34,37.335,8.697767163740266,0,0,1,0,0,0,0,1,0,0 62 | 43,27.36,9.060240174524983,1,0,0,1,0,0,0,0,0,0 63 | 25,33.66,8.41286822827766,1,0,0,0,1,0,0,0,1,0 64 | 64,24.7,10.314491233394307,1,1,0,0,0,0,0,1,0,0 65 | 28,25.935,8.326914052885053,0,1,0,0,0,0,0,1,0,0 66 | 20,22.42,9.596401351776898,0,0,0,0,0,0,1,1,0,0 67 | 19,28.9,7.463485814805136,0,0,0,0,0,0,0,0,0,1 68 | 61,39.1,9.56346405765509,0,0,1,0,0,0,0,0,0,1 69 | 40,26.315,8.762392179564197,1,1,0,0,0,0,0,1,0,0 70 | 40,36.19,8.686109312182905,0,0,0,0,0,0,0,0,1,0 71 | 28,23.98,9.779235499080675,1,0,0,1,0,0,1,0,1,0 72 | 27,24.75,9.715818493302972,0,0,0,0,0,0,1,0,1,0 73 | 31,28.5,8.824598182105163,1,0,0,0,0,1,0,0,0,0 74 | 53,28.1,9.370904101315244,0,0,0,1,0,0,0,0,0,1 75 | 58,32.01,9.388204166026542,1,1,0,0,0,0,0,0,1,0 76 | 44,27.4,8.952457072970553,1,0,1,0,0,0,0,0,0,1 77 | 57,34.01,9.33755971420867,1,0,0,0,0,0,0,1,0,0 78 | 29,29.59,8.280815731954618,0,1,0,0,0,0,0,0,1,0 79 | 21,35.53,7.334635895999898,1,0,0,0,0,0,0,0,1,0 80 | 22,39.805,7.921180325913819,0,0,0,0,0,0,0,0,0,0 81 | 41,32.965,8.790425012567459,0,0,0,0,0,0,0,1,0,0 82 | 31,26.885,8.398682850087193,1,1,0,0,0,0,0,0,0,0 83 | 45,38.285,8.979075324158835,0,0,0,0,0,0,0,0,0,0 84 | 22,37.62,10.52312714452221,1,1,0,0,0,0,1,0,1,0 85 | 48,41.23,9.30870603358349,0,0,0,0,1,0,0,1,0,0 86 | 37,34.8,10.592539333383169,0,0,1,0,0,0,1,0,0,1 87 | 45,22.895,9.956959788679958,1,0,1,0,0,0,1,1,0,0 88 | 57,31.16,10.682329271350698,0,0,0,0,0,0,1,1,0,0 89 | 56,27.2,9.31228088608999,0,0,0,0,0,0,0,0,0,1 90 | 46,27.74,8.990524602449,0,0,0,0,0,0,0,1,0,0 91 | 55,26.98,9.313129532532235,0,0,0,0,0,0,0,1,0,0 92 | 21,39.49,7.614299368866667,0,0,0,0,0,0,0,0,1,0 93 | 53,24.795,9.300375942728616,0,1,0,0,0,0,0,1,0,0 94 | 59,29.83,10.315098294160247,1,0,0,1,0,0,1,0,0,0 95 | 35,34.77,8.653297199525971,1,0,1,0,0,0,0,1,0,0 96 | 64,31.3,10.764076444545346,0,0,1,0,0,0,1,0,0,1 97 | 28,37.62,8.234003360388554,0,1,0,0,0,0,0,0,1,0 98 | 54,30.8,9.401400304380042,0,0,0,1,0,0,0,0,0,1 99 | 55,38.28,9.23271656715675,1,0,0,0,0,0,0,0,1,0 100 | 56,19.95,10.01738074365831,1,0,0,0,0,0,1,0,0,0 101 | 38,19.3,9.669074424922021,1,0,0,0,0,0,1,0,0,1 102 | 41,31.6,8.730064483263822,0,0,0,0,0,0,0,0,0,1 103 | 30,25.46,8.201136170890955,1,0,0,0,0,0,0,0,0,0 104 | 18,30.115,9.968565617156433,0,0,0,0,0,0,0,0,0,0 105 | 61,29.92,10.339875961954133,0,0,0,1,0,0,1,0,1,0 106 | 34,27.5,8.517963494656502,0,1,0,0,0,0,0,0,0,1 107 | 20,28.025,9.773400492809486,1,1,0,0,0,0,1,1,0,0 108 | 19,28.4,7.754275265475304,0,1,0,0,0,0,0,0,0,1 109 | 26,30.875,8.262895410217363,1,0,1,0,0,0,0,1,0,0 110 | 29,27.94,7.961063181092804,1,0,0,0,0,0,0,0,1,0 111 | 63,35.09,10.75908371727273,1,0,0,0,0,0,1,0,1,0 112 | 54,33.63,9.289636989085668,1,1,0,0,0,0,0,1,0,0 113 | 55,29.7,9.382725896148083,0,0,1,0,0,0,0,0,0,1 114 | 37,30.8,8.443925266324161,1,0,0,0,0,0,0,0,0,1 115 | 21,35.72,7.78519449034302,0,0,0,0,0,0,0,1,0,0 116 | 52,32.205,9.349085880566193,1,0,0,1,0,0,0,0,0,0 117 | 60,28.595,10.317581840613983,1,0,0,0,0,0,0,0,0,0 118 | 58,49.06,9.339729168385329,1,0,0,0,0,0,0,0,1,0 119 | 29,27.94,9.857850840007492,0,1,0,0,0,0,1,0,1,0 120 | 49,27.17,9.059672040064365,0,0,0,0,0,0,0,0,1,0 121 | 37,23.37,8.807835572826509,0,0,1,0,0,0,0,1,0,0 122 | 44,37.1,8.954200505687611,1,0,1,0,0,0,0,0,0,1 123 | 18,23.75,7.441686598314886,1,0,0,0,0,0,0,0,0,0 124 | 20,28.975,7.722002321775892,0,0,0,0,0,0,0,1,0,0 125 | 44,31.35,10.585485169575772,1,1,0,0,0,0,1,0,0,0 126 | 47,33.915,9.221775624539674,0,0,0,1,0,0,0,1,0,0 127 | 26,28.785,8.127227095676806,0,0,0,0,0,0,0,0,0,0 128 | 19,28.3,9.745726697193628,0,0,0,0,0,0,1,0,0,1 129 | 52,37.4,9.17310962951719,0,0,0,0,0,0,0,0,0,1 130 | 32,17.765,10.39617526337975,0,0,1,0,0,0,1,1,0,0 131 | 38,34.7,8.71315545595782,1,0,1,0,0,0,0,0,0,1 132 | 59,26.505,9.458406359225453,0,0,0,0,0,0,0,0,0,0 133 | 61,22.04,9.519027187129101,0,0,0,0,0,0,0,0,0,0 134 | 53,35.9,9.320410898099556,0,0,1,0,0,0,0,0,0,1 135 | 19,25.555,7.397907339697485,1,0,0,0,0,0,0,1,0,0 136 | 20,28.785,7.806782306964648,0,0,0,0,0,0,0,0,0,0 137 | 22,28.05,7.675862193843412,0,0,0,0,0,0,0,0,1,0 138 | 19,34.1,7.140010790012643,1,0,0,0,0,0,0,0,0,1 139 | 22,25.175,7.623488097922841,1,0,0,0,0,0,0,1,0,0 140 | 54,31.9,10.215474376760241,0,0,0,1,0,0,0,0,1,0 141 | 22,36.0,7.680975320607154,0,0,0,0,0,0,0,0,0,1 142 | 34,22.42,10.217418517896819,1,0,1,0,0,0,0,0,0,0 143 | 26,32.49,8.157814338064135,1,1,0,0,0,0,0,0,0,0 144 | 34,25.3,9.8507455777387,1,0,1,0,0,0,1,0,1,0 145 | 29,29.735,9.806859684962467,1,0,1,0,0,0,0,1,0,0 146 | 30,28.69,9.940108210589148,1,0,0,1,0,0,1,1,0,0 147 | 29,38.83,8.544469137496163,0,0,0,1,0,0,0,0,1,0 148 | 46,30.495,10.614488183794922,1,0,0,1,0,0,1,1,0,0 149 | 51,37.73,9.19802562579482,0,1,0,0,0,0,0,0,1,0 150 | 53,37.43,9.30197970427461,0,1,0,0,0,0,0,1,0,0 151 | 19,28.4,7.518888936086307,1,1,0,0,0,0,0,0,0,1 152 | 35,24.13,8.54192789092582,1,1,0,0,0,0,0,1,0,0 153 | 48,29.7,8.960549282824834,1,0,0,0,0,0,0,0,1,0 154 | 32,37.145,8.753741464655173,0,0,0,1,0,0,0,0,0,0 155 | 42,23.37,9.901723312178918,0,0,0,0,0,0,1,0,0,0 156 | 40,25.46,8.864632130470248,0,1,0,0,0,0,0,0,0,0 157 | 44,39.52,8.846309985832468,1,0,0,0,0,0,0,1,0,0 158 | 48,24.42,9.962872620540713,1,0,0,0,0,0,1,0,1,0 159 | 18,25.175,9.649767534929675,1,0,0,0,0,0,1,0,0,0 160 | 30,35.53,10.517327873578196,1,0,0,0,0,0,1,0,1,0 161 | 50,27.83,9.890877548576052,0,0,0,1,0,0,0,0,1,0 162 | 42,26.6,9.96874640792068,0,0,0,0,0,0,1,1,0,0 163 | 18,36.85,10.495417939794661,0,0,0,0,0,0,1,0,1,0 164 | 54,39.6,9.25441007896438,1,1,0,0,0,0,0,0,0,1 165 | 32,29.8,8.547166276762724,0,0,1,0,0,0,0,0,0,1 166 | 37,29.64,8.522806726007444,1,0,0,0,0,0,0,1,0,0 167 | 47,28.215,9.250242184859143,1,0,0,0,1,0,0,0,0,0 168 | 20,37.0,8.48273217292335,0,0,0,0,0,1,0,0,0,1 169 | 32,33.155,8.720753835134126,0,0,0,1,0,0,0,1,0,0 170 | 19,31.825,7.908122326430799,0,1,0,0,0,0,0,1,0,0 171 | 27,18.905,8.482167894782533,1,0,0,1,0,0,0,0,0,0 172 | 63,41.47,9.503412166247688,1,0,0,0,0,0,0,0,1,0 173 | 49,30.3,9.00167648255175,1,0,0,0,0,0,0,0,0,1 174 | 18,15.96,7.435317894605706,1,0,0,0,0,0,0,0,0,0 175 | 35,34.8,8.5652301195937,0,1,0,0,0,0,0,0,0,1 176 | 24,33.345,7.956980367790471,0,0,0,0,0,0,0,1,0,0 177 | 63,37.7,10.79598649096049,0,0,0,0,0,0,1,0,0,1 178 | 38,27.835,8.772743934940326,1,0,1,0,0,0,0,1,0,0 179 | 54,29.2,9.253025845141101,1,1,0,0,0,0,0,0,0,1 180 | 46,28.9,9.085148848619458,0,0,1,0,0,0,0,0,0,1 181 | 41,33.155,9.05231585100584,0,0,0,1,0,0,0,0,0,0 182 | 58,28.595,9.370406013873325,1,0,0,0,0,0,0,1,0,0 183 | 18,38.28,7.3974519706985165,0,0,0,0,0,0,0,0,1,0 184 | 22,19.95,8.295404347072033,1,0,0,1,0,0,0,0,0,0 185 | 44,26.41,8.91186396980437,0,0,0,0,0,0,0,1,0,0 186 | 44,30.69,8.95304874291158,1,0,1,0,0,0,0,0,1,0 187 | 36,41.895,10.68632316430551,1,0,0,1,0,0,1,0,0,0 188 | 26,29.92,8.289533658389189,0,0,1,0,0,0,0,0,1,0 189 | 30,30.9,8.5802902366264,0,0,0,1,0,0,0,0,0,1 190 | 41,32.2,8.821136480707299,0,1,0,0,0,0,0,0,0,1 191 | 29,32.11,8.50165629653286,0,0,1,0,0,0,0,1,0,0 192 | 61,31.57,9.438081761016077,1,0,0,0,0,0,0,0,1,0 193 | 36,26.2,8.49369239832677,0,0,0,0,0,0,0,0,0,1 194 | 25,25.74,7.667464057878258,1,0,0,0,0,0,0,0,1,0 195 | 56,26.6,9.396350285080235,0,1,0,0,0,0,0,1,0,0 196 | 18,34.43,7.036561513107688,1,0,0,0,0,0,0,0,1,0 197 | 19,30.59,7.402185082887787,1,0,0,0,0,0,0,1,0,0 198 | 39,32.8,8.639360380390347,0,0,0,0,0,0,0,0,0,1 199 | 45,28.6,9.04979936744745,0,0,1,0,0,0,0,0,1,0 200 | 51,18.05,9.17411742104044,0,0,0,0,0,0,0,1,0,0 201 | 64,39.33,9.60921827869941,0,0,0,0,0,0,0,0,0,0 202 | 19,32.11,7.664194532310539,0,0,0,0,0,0,0,1,0,0 203 | 48,32.23,9.090559909039461,0,1,0,0,0,0,0,0,1,0 204 | 60,24.035,9.473643322662959,0,0,0,0,0,0,0,1,0,0 205 | 27,36.08,10.522285529540705,0,0,0,0,0,0,1,0,1,0 206 | 46,22.3,8.874462658591002,1,0,0,0,0,0,0,0,0,1 207 | 28,28.88,8.375107647568866,0,1,0,0,0,0,0,0,0,0 208 | 59,26.4,9.371038059018279,1,0,0,0,0,0,0,0,1,0 209 | 35,27.74,9.951519982078127,1,0,1,0,0,0,1,0,0,0 210 | 63,31.8,9.538272603481479,0,0,0,0,0,0,0,0,0,1 211 | 40,41.23,8.796355528774585,1,1,0,0,0,0,0,0,0,0 212 | 20,33.0,7.590887476599013,1,1,0,0,0,0,0,0,0,1 213 | 40,30.875,9.007332266342479,1,0,0,0,1,0,0,1,0,0 214 | 24,28.5,8.171232925464038,1,0,1,0,0,0,0,1,0,0 215 | 34,26.73,8.517749576605288,0,1,0,0,0,0,0,0,1,0 216 | 45,30.9,9.050174671461898,0,0,1,0,0,0,0,0,0,1 217 | 41,37.1,8.905413390476387,0,0,1,0,0,0,0,0,0,1 218 | 53,26.6,9.245286674376384,0,0,0,0,0,0,0,1,0,0 219 | 27,23.1,7.817519157211993,1,0,0,0,0,0,0,0,1,0 220 | 26,29.92,8.129462927154016,0,1,0,0,0,0,0,0,1,0 221 | 24,23.21,10.12989648030097,0,0,0,0,0,0,0,0,1,0 222 | 34,33.7,8.51968428606193,0,1,0,0,0,0,0,0,0,1 223 | 53,33.25,9.265290997666689,0,0,0,0,0,0,0,0,0,0 224 | 32,30.8,8.566654368501379,1,0,0,1,0,0,0,0,0,1 225 | 19,34.8,10.456786718266788,1,0,0,0,0,0,1,0,0,1 226 | 42,24.64,9.878966432240112,1,0,0,0,0,0,1,0,1,0 227 | 55,33.88,9.39159203997651,1,0,0,1,0,0,0,0,1,0 228 | 28,38.06,7.89710887135675,1,0,0,0,0,0,0,0,1,0 229 | 58,41.91,10.09523691260038,0,0,0,0,0,0,0,0,1,0 230 | 41,31.635,8.90356730735587,0,1,0,0,0,0,0,0,0,0 231 | 47,25.46,9.129700262560421,1,0,1,0,0,0,0,0,0,0 232 | 42,36.195,8.915115665242206,0,1,0,0,0,0,0,1,0,0 233 | 59,27.83,9.54690451151705,0,0,0,1,0,0,0,0,1,0 234 | 19,17.8,7.454595520326733,0,0,0,0,0,0,0,0,0,1 235 | 59,27.5,9.420101010262051,1,1,0,0,0,0,0,0,0,1 236 | 39,24.51,8.811382828662593,1,0,1,0,0,0,0,1,0,0 237 | 40,22.22,9.875307488098656,0,0,1,0,0,0,1,0,1,0 238 | 18,26.73,7.38756485984698,0,0,0,0,0,0,0,0,1,0 239 | 31,38.39,8.403622419208565,1,0,1,0,0,0,0,0,1,0 240 | 19,29.07,9.761502257593413,1,0,0,0,0,0,1,1,0,0 241 | 44,38.06,8.875241188286216,1,1,0,0,0,0,0,0,1,0 242 | 23,36.67,10.558715508439093,0,0,1,0,0,0,1,0,0,0 243 | 33,22.135,8.585613166829567,0,1,0,0,0,0,0,0,0,0 244 | 55,26.8,10.467668179152426,0,1,0,0,0,0,0,0,0,1 245 | 40,35.3,8.881401071414858,1,0,0,1,0,0,0,0,0,1 246 | 63,27.74,10.292930508737422,0,0,0,0,0,0,1,0,0,0 247 | 54,30.02,10.105467874562926,1,0,0,0,0,0,0,1,0,0 248 | 60,38.06,9.44530999087867,0,0,0,0,0,0,0,0,1,0 249 | 24,35.86,7.594347724123951,1,0,0,0,0,0,0,0,1,0 250 | 19,20.9,7.513214853961428,1,1,0,0,0,0,0,0,0,1 251 | 29,28.975,8.304138142102193,1,1,0,0,0,0,0,0,0,0 252 | 18,17.29,9.459498985936145,1,0,1,0,0,0,1,0,0,0 253 | 63,32.2,10.764377724639163,0,0,1,0,0,0,1,0,0,1 254 | 54,34.21,10.697853556525223,1,0,1,0,0,0,1,0,1,0 255 | 27,30.3,8.357199071901574,1,0,0,1,0,0,0,0,0,1 256 | 50,31.825,10.623694340922153,1,0,0,0,0,0,1,0,0,0 257 | 55,25.365,9.476338974230188,0,0,0,1,0,0,0,0,0,0 258 | 56,33.63,10.690152027095278,1,0,0,0,0,0,1,1,0,0 259 | 38,40.15,8.594335790143862,0,0,0,0,0,0,0,0,1,0 260 | 51,24.415,9.351848601747042,1,0,0,0,1,0,0,1,0,0 261 | 19,31.92,10.426744342189226,1,0,0,0,0,0,1,1,0,0 262 | 58,25.2,9.378999014800954,0,0,0,0,0,0,0,0,0,1 263 | 20,26.84,9.74597182728889,0,1,0,0,0,0,1,0,1,0 264 | 52,24.32,10.12141097465288,1,0,0,1,0,0,1,0,0,0 265 | 19,36.955,10.497350316338569,1,0,0,0,0,0,1,1,0,0 266 | 53,38.06,9.926373541970088,0,0,0,1,0,0,0,0,1,0 267 | 46,42.35,10.739676605831331,1,0,0,1,0,0,1,0,1,0 268 | 40,19.8,9.75147337210112,1,1,0,0,0,0,1,0,1,0 269 | 59,32.395,9.588134961346164,0,0,0,1,0,0,0,0,0,0 270 | 45,30.2,8.914767650070457,1,1,0,0,0,0,0,0,0,1 271 | 49,25.84,9.135884096094836,1,1,0,0,0,0,0,0,0,0 272 | 18,29.37,7.449751783533308,1,1,0,0,0,0,0,0,1,0 273 | 50,34.2,10.665620491224391,1,0,1,0,0,0,1,0,0,1 274 | 41,37.05,8.890920267819599,1,0,1,0,0,0,0,1,0,0 275 | 50,27.455,9.17135652556776,1,1,0,0,0,0,0,0,0,0 276 | 25,27.55,7.833271128310732,1,0,0,0,0,0,0,1,0,0 277 | 47,26.6,9.181512925228999,0,0,1,0,0,0,0,0,0,0 278 | 19,20.615,7.938694485572268,1,0,1,0,0,0,0,1,0,0 279 | 22,24.3,7.673441236867624,0,0,0,0,0,0,0,0,0,1 280 | 59,31.79,9.467211971648577,1,0,1,0,0,0,0,0,1,0 281 | 51,21.56,9.195747552831266,0,1,0,0,0,0,0,0,1,0 282 | 40,28.12,10.01375650806908,0,1,0,0,0,0,1,0,0,0 283 | 54,40.565,10.790332549786354,1,0,0,1,0,0,1,0,0,0 284 | 30,27.645,8.351640618011537,1,1,0,0,0,0,0,0,0,0 285 | 55,32.395,9.38253617340599,0,1,0,0,0,0,0,0,0,0 286 | 52,31.2,9.172214739003671,0,0,0,0,0,0,0,0,0,1 287 | 46,26.62,8.954429513418837,1,1,0,0,0,0,0,0,1,0 288 | 46,48.07,9.15196153961076,0,0,1,0,0,0,0,0,0,0 289 | 63,26.22,9.564946673749331,0,0,0,0,0,0,0,1,0,0 290 | 59,36.765,10.776803794725254,0,1,0,0,0,0,1,0,0,0 291 | 52,26.4,10.16557566503102,1,0,0,1,0,0,0,0,1,0 292 | 28,33.4,8.062123257391853,0,0,0,0,0,0,0,0,0,1 293 | 29,29.64,9.917282340913964,1,1,0,0,0,0,0,0,0,0 294 | 25,45.54,10.648093609274202,1,0,1,0,0,0,1,0,1,0 295 | 22,28.82,7.67635857254542,0,0,0,0,0,0,0,0,1,0 296 | 25,26.8,8.270301624988955,1,0,0,1,0,0,0,0,0,1 297 | 18,22.99,7.44106704384527,1,0,0,0,0,0,0,0,0,0 298 | 19,27.7,9.698788230823375,1,0,0,0,0,0,1,0,0,1 299 | 47,25.41,9.99782803051339,1,1,0,0,0,0,1,0,1,0 300 | 31,34.39,10.564791968421908,1,0,0,1,0,0,1,1,0,0 301 | 48,28.88,9.132324256044338,0,1,0,0,0,0,0,1,0,0 302 | 36,27.55,8.8168150747887,1,0,0,1,0,0,0,0,0,0 303 | 53,22.61,10.121553631275622,0,0,0,1,0,0,1,0,0,0 304 | 56,37.51,9.414546284823487,0,0,1,0,0,0,0,0,1,0 305 | 28,33.0,8.377807438273036,0,0,1,0,0,0,0,0,1,0 306 | 57,38.0,9.445112607296863,0,0,1,0,0,0,0,0,0,1 307 | 29,33.345,9.87520913550149,1,0,1,0,0,0,0,1,0,0 308 | 28,27.5,9.912331882391653,0,0,1,0,0,0,0,0,0,1 309 | 30,33.33,8.331111462025765,0,1,0,0,0,0,0,0,1,0 310 | 58,34.865,9.38803409936744,1,0,0,0,0,0,0,0,0,0 311 | 41,33.06,8.955339264809723,0,0,1,0,0,0,0,1,0,0 312 | 50,26.6,9.041267541926123,1,0,0,0,0,0,0,0,0,1 313 | 19,24.7,7.460131207985733,0,0,0,0,0,0,0,0,0,1 314 | 43,35.97,10.648385161357012,1,0,0,1,0,0,1,0,1,0 315 | 49,35.86,9.002628192239301,1,0,0,0,0,0,0,0,1,0 316 | 27,31.4,10.458489082567231,0,0,0,0,0,0,1,0,0,1 317 | 52,33.25,9.182225784853754,1,0,0,0,0,0,0,0,0,0 318 | 50,32.205,9.086506372985527,1,0,0,0,0,0,0,1,0,0 319 | 54,32.775,9.25292707248648,1,0,0,0,0,0,0,0,0,0 320 | 44,27.645,8.912095313769873,0,0,0,0,0,0,0,1,0,0 321 | 32,37.335,8.448401938888532,1,1,0,0,0,0,0,0,0,0 322 | 34,25.27,8.495919155328892,1,1,0,0,0,0,0,1,0,0 323 | 26,29.64,10.11341063084194,0,0,0,0,1,0,0,0,0,0 324 | 34,30.8,10.47705245477294,1,0,0,0,0,0,1,0,0,1 325 | 57,40.945,9.35585102402813,1,0,0,0,0,0,0,0,0,0 326 | 29,27.2,7.960704359454179,1,0,0,0,0,0,0,0,0,1 327 | 40,34.105,8.79485613207312,1,1,0,0,0,0,0,0,0,0 328 | 27,23.21,8.178046273020675,0,1,0,0,0,0,0,0,1,0 329 | 45,36.48,10.663370109691156,1,0,1,0,0,0,1,1,0,0 330 | 64,33.8,10.777455789702474,0,1,0,0,0,0,1,0,0,1 331 | 52,36.7,9.120914992717132,1,0,0,0,0,0,0,0,0,1 332 | 61,36.385,10.789681138177611,0,1,0,0,0,0,1,0,0,0 333 | 52,27.36,10.102077000067178,1,0,0,0,0,0,1,1,0,0 334 | 61,31.16,9.505174462663783,0,0,0,0,0,0,0,1,0,0 335 | 56,28.785,9.363780440807814,0,0,0,0,0,0,0,0,0,0 336 | 43,35.72,9.859774744053276,0,0,1,0,0,0,0,0,0,0 337 | 64,34.5,9.534074898753166,1,0,0,0,0,0,0,0,0,1 338 | 60,25.74,9.404473447330512,1,0,0,0,0,0,0,0,1,0 339 | 62,27.55,9.54235027431946,1,1,0,0,0,0,0,1,0,0 340 | 50,32.3,10.643496777732379,1,1,0,0,0,0,1,0,0,0 341 | 46,27.72,9.015861874114465,0,1,0,0,0,0,0,0,1,0 342 | 24,27.6,9.849834643287883,0,0,0,0,0,0,0,0,0,1 343 | 62,30.02,9.499428939849388,1,0,0,0,0,0,0,1,0,0 344 | 60,27.55,9.489266308614972,0,0,0,0,0,0,0,0,0,0 345 | 63,36.765,9.545515363967878,1,0,0,0,0,0,0,0,0,0 346 | 49,41.47,9.303576247352384,0,0,0,0,1,0,0,0,1,0 347 | 34,29.26,8.729769004360477,0,0,0,1,0,0,0,0,1,0 348 | 33,35.75,8.494947480219423,1,0,1,0,0,0,0,0,1,0 349 | 46,33.345,9.028153712083231,1,1,0,0,0,0,0,0,0,0 350 | 36,29.92,8.608502067580671,0,1,0,0,0,0,0,0,1,0 351 | 19,27.835,7.3998466982849465,1,0,0,0,0,0,0,1,0,0 352 | 57,23.18,9.378445282789643,0,0,0,0,0,0,0,1,0,0 353 | 50,25.6,9.097405017304542,0,0,0,0,0,0,0,0,0,1 354 | 30,27.7,8.175886125822831,0,0,0,0,0,0,0,0,0,1 355 | 33,35.245,9.425845150008275,1,0,0,0,0,0,0,0,0,0 356 | 18,38.28,9.556270438418146,0,0,0,0,0,0,0,0,1,0 357 | 46,27.6,10.110625631722993,1,0,0,0,0,0,0,0,0,1 358 | 46,43.89,9.09875106427451,1,0,0,1,0,0,0,0,1,0 359 | 47,29.83,9.171633919368277,1,0,0,1,0,0,0,1,0,0 360 | 23,41.91,7.516042530164765,1,0,0,0,0,0,0,0,1,0 361 | 18,20.79,7.382441739140248,0,0,0,0,0,0,0,0,1,0 362 | 48,32.3,9.214655946474418,0,0,1,0,0,0,0,0,0,0 363 | 35,30.5,8.466125134818647,1,1,0,0,0,0,0,0,0,1 364 | 19,21.7,9.535643754217315,0,0,0,0,0,0,1,0,0,1 365 | 21,26.4,7.862412128177326,0,1,0,0,0,0,0,0,0,1 366 | 21,21.89,8.064796871715137,0,0,1,0,0,0,0,0,1,0 367 | 49,30.78,9.18792575079209,0,1,0,0,0,0,0,0,0,0 368 | 56,32.3,9.50526602126602,0,0,0,1,0,0,0,0,0,0 369 | 42,24.985,8.989327193555336,0,0,1,0,0,0,0,1,0,0 370 | 44,32.015,9.001625826321154,1,0,1,0,0,0,0,1,0,0 371 | 18,30.4,8.155324210362002,1,0,0,1,0,0,0,0,0,0 372 | 61,21.09,9.504131602960053,0,0,0,0,0,0,0,1,0,0 373 | 57,22.23,9.395099513777716,0,0,0,0,0,0,0,0,0,0 374 | 42,33.155,8.941076629253388,0,1,0,0,0,0,0,0,0,0 375 | 26,32.9,10.493638614491699,1,0,1,0,0,0,1,0,0,1 376 | 20,33.33,7.238158205977826,1,0,0,0,0,0,0,0,1,0 377 | 23,28.31,9.800012364087102,0,0,0,0,0,0,1,1,0,0 378 | 39,24.89,9.98321929340296,0,0,0,1,0,0,1,0,0,0 379 | 24,40.15,10.548658208457207,1,0,0,0,0,0,1,0,1,0 380 | 64,30.115,9.708427677772185,0,0,0,1,0,0,0,1,0,0 381 | 62,31.46,10.203628615802879,1,1,0,0,0,0,0,0,1,0 382 | 27,17.955,9.61624401391433,0,0,1,0,0,0,1,0,0,0 383 | 55,30.685,10.652629646095242,1,0,0,0,0,0,1,0,0,0 384 | 55,33.0,9.94181791367443,1,0,0,0,0,0,0,0,1,0 385 | 35,43.34,8.673669895379257,0,0,1,0,0,0,0,0,1,0 386 | 44,22.135,9.024316247129066,1,0,1,0,0,0,0,0,0,0 387 | 19,34.4,7.140341309442387,1,0,0,0,0,0,0,0,0,1 388 | 58,39.05,9.380624055098195,0,0,0,0,0,0,0,0,1,0 389 | 50,25.365,10.318396029350497,1,0,1,0,0,0,0,1,0,0 390 | 26,22.61,8.06363468484103,0,0,0,0,0,0,0,1,0,0 391 | 24,30.21,8.437734291627043,0,0,0,1,0,0,0,1,0,0 392 | 48,35.625,9.281438961548512,1,0,0,0,1,0,0,0,0,0 393 | 19,37.43,7.667659159326367,0,0,0,0,0,0,0,1,0,0 394 | 48,31.445,9.10097858969497,1,1,0,0,0,0,0,0,0,0 395 | 49,31.35,9.136708847841536,1,1,0,0,0,0,0,0,0,0 396 | 46,32.3,9.149635028151815,0,0,1,0,0,0,0,0,0,0 397 | 46,19.855,8.926212834672594,1,0,0,0,0,0,0,1,0,0 398 | 43,34.4,9.050406686089836,0,0,0,1,0,0,0,0,0,1 399 | 21,31.02,9.716344252398859,1,0,0,0,0,0,0,0,1,0 400 | 64,25.6,9.615033982556648,1,0,1,0,0,0,0,0,0,1 401 | 18,38.17,7.3973582673174505,0,0,0,0,0,0,0,0,1,0 402 | 51,20.6,9.13397722806388,0,0,0,0,0,0,0,0,0,1 403 | 47,47.52,8.997632157643029,1,1,0,0,0,0,0,0,1,0 404 | 64,32.965,9.5951039647093,0,0,0,0,0,0,0,1,0,0 405 | 49,32.3,9.23692972120915,1,0,0,1,0,0,0,1,0,0 406 | 31,20.4,8.089543515442493,1,0,0,0,0,0,0,0,0,1 407 | 52,38.38,9.341096685127038,0,0,1,0,0,0,0,0,0,0 408 | 33,24.31,8.339285375720452,0,0,0,0,0,0,0,0,1,0 409 | 47,23.6,9.05247776145036,0,1,0,0,0,0,0,0,0,1 410 | 38,21.12,8.802752332042022,1,0,0,1,0,0,0,0,1,0 411 | 32,30.03,8.312491955338244,1,1,0,0,0,0,0,0,1,0 412 | 19,17.48,7.391008370166293,1,0,0,0,0,0,0,1,0,0 413 | 44,20.235,9.88301999637374,0,1,0,0,0,0,1,0,0,0 414 | 26,17.195,9.578840208975,0,0,1,0,0,0,1,0,0,0 415 | 25,23.9,8.533085438031765,1,0,0,0,0,1,0,0,0,1 416 | 19,35.15,7.6661757887670525,0,0,0,0,0,0,0,1,0,0 417 | 43,35.64,8.901874008153671,0,1,0,0,0,0,0,0,1,0 418 | 52,34.1,9.120519707175607,1,0,0,0,0,0,0,0,1,0 419 | 36,22.6,9.83136095462493,0,0,1,0,0,0,1,0,0,1 420 | 64,39.16,9.576252152687747,1,1,0,0,0,0,0,0,1,0 421 | 63,26.98,10.273341690123692,0,0,0,0,0,0,1,1,0,0 422 | 64,33.88,10.755543955934765,1,0,0,0,0,0,1,0,1,0 423 | 61,35.86,10.749336686883488,1,0,0,0,0,0,1,0,1,0 424 | 40,32.775,10.574525419819176,1,1,0,0,0,0,1,0,0,0 425 | 25,30.59,7.9111022568392935,1,0,0,0,0,0,0,0,0,0 426 | 48,30.2,9.101454761577214,1,0,1,0,0,0,0,0,0,1 427 | 45,24.31,9.189000886117643,1,0,0,0,0,1,0,0,1,0 428 | 38,27.265,8.787994128405655,0,1,0,0,0,0,0,0,0,0 429 | 18,29.165,8.898875698011654,0,0,0,0,0,0,0,0,0,0 430 | 21,16.815,8.0606839736609,0,1,0,0,0,0,0,0,0,0 431 | 27,30.4,9.841864904106775,0,0,0,1,0,0,0,1,0,0 432 | 19,33.1,10.046849759651726,1,0,0,0,0,0,0,0,0,1 433 | 29,20.235,8.498297721128688,0,0,1,0,0,0,0,1,0,0 434 | 42,26.9,8.69445580665023,1,0,0,0,0,0,0,0,0,1 435 | 60,30.5,9.444478856870957,0,0,0,0,0,0,0,0,0,1 436 | 31,28.595,8.353164899875043,1,1,0,0,0,0,0,1,0,0 437 | 60,33.11,9.541069211106327,1,0,0,1,0,0,0,0,1,0 438 | 22,31.73,7.72081509266191,1,0,0,0,0,0,0,0,0,0 439 | 35,28.9,8.68724747865966,1,0,0,1,0,0,0,0,0,1 440 | 52,46.75,9.44085941734208,0,0,0,0,0,1,0,0,1,0 441 | 26,29.45,7.971542658777002,1,0,0,0,0,0,0,0,0,0 442 | 31,32.68,8.4634269892796,0,1,0,0,0,0,0,1,0,0 443 | 33,33.5,10.52081608318254,0,0,0,0,0,0,1,0,0,1 444 | 18,43.01,7.0469917789888035,1,0,0,0,0,0,0,0,1,0 445 | 59,36.52,10.250189347642364,0,1,0,0,0,0,0,0,1,0 446 | 56,26.695,10.170047964312062,1,1,0,0,0,0,1,1,0,0 447 | 45,33.1,8.901786524893842,0,0,0,0,0,0,0,0,0,1 448 | 60,29.64,9.451795211642274,1,0,0,0,0,0,0,0,0,0 449 | 56,25.65,9.346096170025552,0,0,0,0,0,0,0,1,0,0 450 | 40,29.6,8.6845608269172,0,0,0,0,0,0,0,0,0,1 451 | 35,38.6,8.468492113278527,1,1,0,0,0,0,0,0,0,1 452 | 39,29.6,8.924292563387446,1,0,0,0,1,0,0,0,0,1 453 | 30,24.13,8.30207750539002,1,1,0,0,0,0,0,1,0,0 454 | 24,23.4,7.585592863447169,1,0,0,0,0,0,0,0,0,1 455 | 20,29.735,7.478470186034148,1,0,0,0,0,0,0,1,0,0 456 | 32,46.53,8.45241756483806,1,0,1,0,0,0,0,0,1,0 457 | 59,37.4,9.989527642979661,1,0,0,0,0,0,0,0,0,1 458 | 55,30.14,9.382777370420577,0,0,1,0,0,0,0,0,1,0 459 | 57,30.495,9.37930436659962,0,0,0,0,0,0,0,1,0,0 460 | 56,39.6,9.268742478775991,1,0,0,0,0,0,0,0,0,1 461 | 40,33.0,8.946722421973286,0,0,0,1,0,0,0,0,1,0 462 | 49,36.63,9.247778603221294,0,0,0,1,0,0,0,0,1,0 463 | 42,30.0,10.005323303503058,1,0,0,0,0,0,1,0,0,1 464 | 62,38.095,9.631043722747554,0,0,1,0,0,0,0,0,0,0 465 | 56,25.935,9.320576570650314,1,0,0,0,0,0,0,0,0,0 466 | 19,25.175,7.3975837472871735,1,0,0,0,0,0,0,1,0,0 467 | 30,28.38,9.879295684802122,0,1,0,0,0,0,1,0,1,0 468 | 60,28.7,9.489841042846475,0,1,0,0,0,0,0,0,0,1 469 | 56,33.82,9.44488886301366,0,0,1,0,0,0,0,1,0,0 470 | 28,24.32,10.05573335065625,0,1,0,0,0,0,0,0,0,0 471 | 18,24.09,7.6967111968641335,0,1,0,0,0,0,0,0,1,0 472 | 27,32.67,7.822860628568228,1,0,0,0,0,0,0,0,1,0 473 | 18,30.115,7.697789509069965,0,0,0,0,0,0,0,0,0,0 474 | 19,29.8,7.464203197370246,0,0,0,0,0,0,0,0,0,1 475 | 47,33.345,9.94648882334788,0,0,0,0,0,0,0,0,0,0 476 | 54,25.1,10.14180724150723,1,0,0,1,0,0,1,0,0,1 477 | 61,28.31,10.27051199171073,1,1,0,0,0,0,1,1,0,0 478 | 24,28.5,10.467309581253186,1,0,0,0,0,0,1,0,0,0 479 | 25,35.625,7.837709735550147,1,0,0,0,0,0,0,1,0,0 480 | 21,36.85,7.335832462880444,1,0,0,0,0,0,0,0,1,0 481 | 23,32.56,7.508943627692479,1,0,0,0,0,0,0,0,1,0 482 | 63,41.325,9.652149543620059,1,0,0,1,0,0,0,1,0,0 483 | 49,37.51,9.138275132023676,1,0,1,0,0,0,0,0,1,0 484 | 18,31.35,7.391531442472909,0,0,0,0,0,0,0,0,1,0 485 | 51,39.5,9.198274673309323,0,1,0,0,0,0,0,0,0,1 486 | 48,34.3,9.16565979686612,1,0,0,1,0,0,0,0,0,1 487 | 31,31.065,8.377246602494955,0,0,0,0,0,0,0,0,0,0 488 | 54,21.47,9.431510080543866,0,0,0,1,0,0,0,1,0,0 489 | 19,28.7,7.134042683207834,1,0,0,0,0,0,0,0,0,1 490 | 44,38.06,10.797228653997497,0,0,0,0,0,0,1,0,1,0 491 | 53,31.16,9.255502954897839,1,1,0,0,0,0,0,1,0,0 492 | 19,32.9,7.466670249974151,0,0,0,0,0,0,0,0,0,1 493 | 61,25.08,10.106962590968418,0,0,0,0,0,0,0,0,1,0 494 | 18,25.08,7.69460826211217,0,0,0,0,0,0,0,0,0,0 495 | 61,43.4,9.439390365865586,1,0,0,0,0,0,0,0,0,1 496 | 21,25.7,9.794905520027315,1,0,0,0,1,0,1,0,0,1 497 | 20,27.93,7.584276358739348,1,0,0,0,0,0,0,0,0,0 498 | 31,23.6,8.503428288324521,0,0,1,0,0,0,0,0,0,1 499 | 45,28.7,8.990686723859456,1,0,1,0,0,0,0,0,0,1 500 | 44,23.98,9.013242200776457,0,0,1,0,0,0,0,0,1,0 501 | 62,39.2,9.508284112949143,0,0,0,0,0,0,0,0,0,1 502 | 29,34.4,10.496750832257703,1,0,0,0,0,0,1,0,0,1 503 | 43,26.03,8.830158243620813,1,0,0,0,0,0,0,0,0,0 504 | 51,23.21,10.008663221610878,1,1,0,0,0,0,1,0,1,0 505 | 19,30.25,10.390481663234114,1,0,0,0,0,0,1,0,1,0 506 | 38,28.93,8.695236392417504,0,1,0,0,0,0,0,0,1,0 507 | 37,30.875,8.824216497974023,1,0,0,1,0,0,0,1,0,0 508 | 22,31.35,7.879771498547758,1,1,0,0,0,0,0,1,0,0 509 | 21,23.75,8.031741411564495,1,0,1,0,0,0,0,1,0,0 510 | 24,25.27,8.020997788799955,0,0,0,0,0,0,0,0,0,0 511 | 57,28.7,9.346206038063324,0,0,0,0,0,0,0,0,0,1 512 | 56,32.11,9.372714367471533,1,1,0,0,0,0,0,0,0,0 513 | 27,33.66,7.82341156964102,1,0,0,0,0,0,0,0,1,0 514 | 51,22.42,9.144342311562506,1,0,0,0,0,0,0,0,0,0 515 | 19,30.4,7.135925376021836,1,0,0,0,0,0,0,0,0,1 516 | 39,28.3,9.956182464199104,1,1,0,0,0,0,1,0,0,1 517 | 58,35.7,9.338096180478136,1,0,0,0,0,0,0,0,0,1 518 | 20,35.31,10.230064158147394,1,1,0,0,0,0,0,0,1,0 519 | 45,30.495,9.037588445855505,1,0,1,0,0,0,0,1,0,0 520 | 35,31.0,8.564222759025652,0,1,0,0,0,0,0,0,0,1 521 | 31,30.875,8.25784178871916,1,0,0,0,0,0,0,0,0,0 522 | 50,27.36,10.152555163167145,0,0,0,0,0,0,0,0,0,0 523 | 32,44.22,8.29259302976008,0,0,0,0,0,0,0,0,1,0 524 | 51,33.915,9.19688068036355,0,0,0,0,0,0,0,0,0,0 525 | 38,37.73,8.593712783276118,0,0,0,0,0,0,0,0,1,0 526 | 42,26.07,10.551783623990207,1,1,0,0,0,0,1,0,1,0 527 | 18,33.88,9.348591160089185,0,0,0,0,0,0,0,0,1,0 528 | 19,30.59,10.088292697254127,0,0,1,0,0,0,0,1,0,0 529 | 51,25.8,9.19634539756895,0,1,0,0,0,0,0,0,0,1 530 | 46,39.425,9.029167205529545,1,1,0,0,0,0,0,0,0,0 531 | 18,25.46,7.44307919402031,1,0,0,0,0,0,0,0,0,0 532 | 57,42.13,10.792931466033865,1,1,0,0,0,0,1,0,1,0 533 | 62,31.73,9.549913275130127,0,0,0,0,0,0,0,0,0,0 534 | 59,29.7,9.46698724635025,1,0,1,0,0,0,0,0,1,0 535 | 37,36.19,9.86343117787501,1,0,0,0,0,0,0,0,1,0 536 | 64,40.48,9.534676057705775,1,0,0,0,0,0,0,0,1,0 537 | 38,28.025,8.710640419433316,1,1,0,0,0,0,0,0,0,0 538 | 33,38.9,8.694900452034446,0,0,0,1,0,0,0,0,0,1 539 | 46,30.2,9.085353626796508,0,0,1,0,0,0,0,0,0,1 540 | 46,28.05,9.015917589813023,0,1,0,0,0,0,0,0,1,0 541 | 53,31.35,10.216327083301252,1,0,0,0,0,0,0,0,1,0 542 | 34,38.0,8.731731503635617,0,0,0,1,0,0,0,0,0,1 543 | 20,31.79,8.024989138296391,0,0,1,0,0,0,0,0,1,0 544 | 63,36.3,9.538723119589323,0,0,0,0,0,0,0,0,1,0 545 | 54,47.41,11.063044851063491,0,0,0,0,0,0,1,0,1,0 546 | 54,30.21,9.233226465989146,1,0,0,0,0,0,0,1,0,0 547 | 49,25.84,10.077745040282705,1,0,1,0,0,0,1,1,0,0 548 | 28,35.435,8.092192495253741,1,0,0,0,0,0,0,0,0,0 549 | 54,46.7,9.35343770227735,0,0,1,0,0,0,0,0,0,1 550 | 25,28.595,8.075153944485312,0,0,0,0,0,0,0,0,0,0 551 | 43,46.2,10.733418440581366,0,0,0,0,0,0,1,0,1,0 552 | 63,30.8,9.502305185386628,1,0,0,0,0,0,0,0,0,1 553 | 32,28.93,8.287257802702698,0,0,0,0,0,0,0,0,1,0 554 | 62,21.4,9.469400568633725,1,0,0,0,0,0,0,0,0,1 555 | 52,31.73,9.322566369188928,0,0,1,0,0,0,0,1,0,0 556 | 25,41.325,9.791376563615858,0,0,0,0,0,0,0,0,0,0 557 | 28,23.8,8.255224088861992,1,0,1,0,0,0,0,0,0,1 558 | 46,33.44,9.028169555820288,1,1,0,0,0,0,0,0,0,0 559 | 34,34.21,8.27771187772261,1,0,0,0,0,0,0,0,1,0 560 | 35,34.105,10.596220295978874,0,0,0,1,0,0,1,1,0,0 561 | 19,35.53,7.406364404275679,1,0,0,0,0,0,0,1,0,0 562 | 46,19.95,9.126288810408107,0,0,1,0,0,0,0,1,0,0 563 | 54,32.68,9.298711367598699,0,0,0,0,0,0,0,0,0,0 564 | 27,30.5,7.821651947371885,1,0,0,0,0,0,0,0,0,1 565 | 50,44.77,9.11148424572815,1,1,0,0,0,0,0,0,1,0 566 | 18,32.12,7.93782416656491,0,0,1,0,0,0,0,0,1,0 567 | 19,30.495,7.663140391039033,0,0,0,0,0,0,0,1,0,0 568 | 38,40.565,8.759913046378147,0,1,0,0,0,0,0,1,0,0 569 | 41,30.59,8.889683642287249,1,0,1,0,0,0,0,1,0,0 570 | 49,31.9,9.354692112918501,0,0,0,0,0,1,0,0,0,1 571 | 48,40.565,10.729897828638402,1,0,1,0,0,0,1,1,0,0 572 | 31,29.1,8.232517794382408,0,0,0,0,0,0,0,0,0,1 573 | 18,37.29,7.705012488667424,0,1,0,0,0,0,0,0,1,0 574 | 30,43.12,8.466665246179556,0,0,1,0,0,0,0,0,1,0 575 | 62,36.86,10.361545144286548,0,1,0,0,0,0,0,0,0,0 576 | 57,34.295,9.489792953617386,0,0,1,0,0,0,0,0,0,0 577 | 58,27.17,9.411066381363035,0,0,0,0,0,0,0,1,0,0 578 | 22,26.84,7.417580162174275,1,0,0,0,0,0,0,0,1,0 579 | 31,38.095,10.977996244143489,0,1,0,0,0,0,1,0,0,0 580 | 52,30.2,9.182406838269918,1,1,0,0,0,0,0,0,0,1 581 | 25,23.465,8.072932580939872,0,0,0,0,0,0,0,0,0,0 582 | 59,25.46,9.466066684677644,1,1,0,0,0,0,0,0,0,0 583 | 19,30.59,7.402185082887787,1,0,0,0,0,0,0,1,0,0 584 | 39,45.43,8.757197116428735,1,0,1,0,0,0,0,0,1,0 585 | 32,23.65,9.777143952016166,0,1,0,0,0,0,0,0,1,0 586 | 19,20.7,7.125135051591155,1,0,0,0,0,0,0,0,0,1 587 | 33,28.27,8.4721126211873,0,1,0,0,0,0,0,0,1,0 588 | 21,20.235,8.258735794194376,1,0,0,1,0,0,0,0,0,0 589 | 34,30.21,10.69066855552094,0,1,0,0,0,0,1,1,0,0 590 | 61,35.91,9.520442078197085,0,0,0,0,0,0,0,0,0,0 591 | 38,30.69,8.695645790101407,0,1,0,0,0,0,0,0,1,0 592 | 58,29.0,9.37944513717139,0,0,0,0,0,0,0,0,0,1 593 | 47,19.57,9.039322997481637,1,1,0,0,0,0,0,1,0,0 594 | 20,31.13,7.850286965609456,1,0,1,0,0,0,0,0,1,0 595 | 21,21.85,9.639463704220857,0,1,0,0,0,0,1,0,0,0 596 | 41,40.26,8.649827952186532,1,0,0,0,0,0,0,0,1,0 597 | 46,33.725,9.085228946018162,0,1,0,0,0,0,0,0,0,0 598 | 42,29.48,8.941193352545817,0,0,1,0,0,0,0,0,1,0 599 | 34,33.25,8.629601006423735,0,1,0,0,0,0,0,0,0,0 600 | 43,32.6,8.914827854790714,1,0,1,0,0,0,0,0,0,1 601 | 52,37.525,10.418463707617837,0,0,1,0,0,0,0,1,0,0 602 | 18,39.16,7.398201281823135,0,0,0,0,0,0,0,0,1,0 603 | 51,31.635,9.124143461400536,1,0,0,0,0,0,0,1,0,0 604 | 56,25.3,9.312042353351504,0,0,0,0,0,0,0,0,0,1 605 | 64,39.05,9.685650366281438,0,0,0,1,0,0,0,0,1,0 606 | 19,28.31,9.768182238872198,0,0,0,0,0,0,1,1,0,0 607 | 51,34.1,9.13600058834087,0,0,0,0,0,0,0,0,1,0 608 | 27,25.175,8.177128178496606,0,0,0,0,0,0,0,0,0,0 609 | 59,23.655,10.15342018852608,0,0,0,0,0,0,1,1,0,0 610 | 28,26.98,8.3973041346534,1,0,1,0,0,0,0,0,0,0 611 | 30,37.8,10.577488661220206,1,0,1,0,0,0,1,0,0,1 612 | 47,29.37,9.053416502076113,0,1,0,0,0,0,0,0,1,0 613 | 38,34.8,8.790504091479043,0,0,1,0,0,0,0,0,0,1 614 | 18,33.155,7.6997053735517555,0,0,0,0,0,0,0,0,0,0 615 | 34,19.0,8.817747756687693,0,0,0,1,0,0,0,0,0,0 616 | 20,33.0,7.539064289173378,0,0,0,0,0,0,0,0,1,0 617 | 47,36.63,10.66825404879016,0,1,0,0,0,0,1,0,1,0 618 | 56,28.595,9.36375778731645,0,0,0,0,0,0,0,0,0,0 619 | 49,25.6,10.056489587208766,1,0,1,0,0,0,1,0,0,1 620 | 19,33.11,10.446969774444645,0,0,0,0,0,0,1,0,1,0 621 | 55,37.1,9.279273348336124,0,0,0,0,0,0,0,0,0,1 622 | 30,31.4,8.205039721904125,1,1,0,0,0,0,0,0,0,1 623 | 37,34.1,10.601180535263609,1,0,0,0,1,0,1,0,0,1 624 | 49,21.3,9.125018839122639,0,1,0,0,0,0,0,0,0,1 625 | 18,33.535,10.452124453879096,1,0,0,0,0,0,1,0,0,0 626 | 59,28.785,9.403405191869094,1,0,0,0,0,0,0,1,0,0 627 | 29,26.03,8.225895175981947,0,0,0,0,0,0,0,1,0,0 628 | 36,28.88,8.81708905097227,1,0,0,1,0,0,0,0,0,0 629 | 33,42.46,9.334919362287428,1,1,0,0,0,0,0,0,1,0 630 | 58,38.0,9.338377498726558,1,0,0,0,0,0,0,0,0,1 631 | 44,38.95,10.66857063461853,0,0,0,0,0,0,1,1,0,0 632 | 53,36.1,9.218888333830831,1,1,0,0,0,0,0,0,0,1 633 | 24,29.3,7.5897479789915785,1,0,0,0,0,0,0,0,0,1 634 | 29,35.53,8.121679315150935,0,0,0,0,0,0,0,0,1,0 635 | 40,22.705,8.878129436102586,1,0,1,0,0,0,0,0,0,0 636 | 51,39.7,9.147543905912501,1,1,0,0,0,0,0,0,0,1 637 | 64,38.19,9.575742371148683,1,0,0,0,0,0,0,0,0,0 638 | 19,24.51,7.9043761479872545,0,1,0,0,0,0,0,1,0,0 639 | 35,38.095,10.123227167426604,0,0,1,0,0,0,0,0,0,0 640 | 39,26.41,9.910925963832568,1,0,0,0,0,0,1,0,0,0 641 | 56,33.66,9.468785844923541,1,0,0,0,1,0,0,0,1,0 642 | 33,42.4,8.804811711848632,1,0,0,0,0,1,0,0,0,1 643 | 42,28.31,10.397801361193013,1,0,0,1,0,0,1,1,0,0 644 | 61,33.915,9.483710377406176,1,0,0,0,0,0,0,0,0,0 645 | 23,34.96,8.404387562891182,0,0,0,1,0,0,0,1,0,0 646 | 43,35.31,9.84193898210435,1,0,1,0,0,0,0,0,1,0 647 | 48,30.78,9.22435532214995,1,0,0,1,0,0,0,0,0,0 648 | 39,26.22,8.719900342802815,1,1,0,0,0,0,0,1,0,0 649 | 40,23.37,9.018245325851677,0,0,0,1,0,0,0,0,0,0 650 | 18,28.5,7.445550141369896,1,0,0,0,0,0,0,0,0,0 651 | 58,32.965,9.427944879069686,0,0,0,0,0,0,0,0,0,0 652 | 49,42.68,9.190228293204834,0,0,1,0,0,0,0,0,1,0 653 | 53,39.6,9.266693389349228,0,1,0,0,0,0,0,0,1,0 654 | 48,31.13,9.021673449865537,0,0,0,0,0,0,0,0,1,0 655 | 45,36.3,9.05105526685099,0,0,1,0,0,0,0,0,1,0 656 | 59,35.2,9.412834667305264,0,0,0,0,0,0,0,0,1,0 657 | 52,25.3,10.113238583053082,0,0,1,0,0,0,1,0,1,0 658 | 26,42.4,8.134562580426712,0,1,0,0,0,0,0,0,0,1 659 | 27,33.155,8.308621071757383,1,0,1,0,0,0,0,1,0,0 660 | 48,35.91,10.180826075318105,0,1,0,0,0,0,0,0,0,0 661 | 57,28.785,9.574594392516097,0,0,0,0,1,0,0,0,0,0 662 | 37,46.53,8.769604038410412,1,0,0,1,0,0,0,0,1,0 663 | 57,23.98,10.007506839098198,0,1,0,0,0,0,0,0,1,0 664 | 32,31.54,8.54647090561255,0,1,0,0,0,0,0,0,0,0 665 | 18,33.66,7.035620121996789,1,0,0,0,0,0,0,0,1,0 666 | 64,22.99,10.20499538590917,0,0,0,0,0,0,1,0,1,0 667 | 43,38.06,10.658680236746347,1,0,1,0,0,0,1,0,1,0 668 | 49,28.7,9.071475467142518,1,1,0,0,0,0,0,0,0,1 669 | 40,32.775,10.5967180358763,0,0,1,0,0,0,1,1,0,0 670 | 62,32.015,10.730076918460497,1,0,0,0,0,0,1,0,0,0 671 | 40,29.81,8.779593747532871,0,1,0,0,0,0,0,0,1,0 672 | 30,31.57,8.484170350113216,1,0,0,1,0,0,0,0,1,0 673 | 29,31.16,8.279848124253304,0,0,0,0,0,0,0,0,0,0 674 | 36,29.7,8.389298681673813,1,0,0,0,0,0,0,0,1,0 675 | 41,31.02,8.7299341509027,0,0,0,0,0,0,0,0,1,0 676 | 44,43.89,10.740756399353332,0,0,1,0,0,0,1,0,1,0 677 | 45,21.375,8.884996064646055,1,0,0,0,0,0,0,1,0,0 678 | 55,40.81,9.43234734963519,0,0,0,1,0,0,0,0,1,0 679 | 60,31.35,10.739230189883656,1,0,0,1,0,0,1,1,0,0 680 | 56,36.1,9.422507663952521,1,0,0,1,0,0,0,0,0,1 681 | 49,23.18,9.225897056826396,0,0,1,0,0,0,0,1,0,0 682 | 21,17.4,7.857584843424017,0,1,0,0,0,0,0,0,0,1 683 | 19,20.3,7.124687580359468,1,0,0,0,0,0,0,0,0,1 684 | 39,35.3,10.599228616071036,1,0,1,0,0,0,1,0,0,1 685 | 53,24.32,9.196593495154136,1,0,0,0,0,0,0,1,0,0 686 | 33,18.5,8.469267273678248,0,1,0,0,0,0,0,0,0,1 687 | 53,26.41,9.327623451564245,1,0,1,0,0,0,0,0,0,0 688 | 42,26.125,8.952818312588256,1,0,1,0,0,0,0,0,0,0 689 | 40,41.69,8.601304368555676,1,0,0,0,0,0,0,0,1,0 690 | 47,24.1,10.174909898054338,0,1,0,0,0,0,0,0,0,1 691 | 27,31.13,10.457558501942229,1,1,0,0,0,0,1,0,1,0 692 | 21,27.36,7.651649469743594,1,0,0,0,0,0,0,0,0,0 693 | 47,36.2,8.995683828905412,1,1,0,0,0,0,0,0,0,1 694 | 20,32.395,7.767360964960058,1,1,0,0,0,0,0,1,0,0 695 | 24,23.655,7.763432980222679,1,0,0,0,0,0,0,1,0,0 696 | 27,34.8,8.18255898458288,0,1,0,0,0,0,0,0,0,1 697 | 26,40.185,8.071295122479397,0,0,0,0,0,0,0,1,0,0 698 | 53,32.3,10.281460948193155,0,0,1,0,0,0,0,0,0,0 699 | 41,35.75,10.603452576194714,1,1,0,0,0,0,1,0,1,0 700 | 56,33.725,9.303488739474496,1,0,0,0,0,0,0,1,0,0 701 | 23,39.27,8.16069317503393,0,0,1,0,0,0,0,0,1,0 702 | 21,34.87,7.611126168865535,0,0,0,0,0,0,0,0,1,0 703 | 50,44.745,9.163426479258085,0,0,0,0,0,0,0,0,0,0 704 | 53,41.47,9.15950069048022,1,0,0,0,0,0,0,0,1,0 705 | 34,26.41,8.591435335997009,0,1,0,0,0,0,0,1,0,0 706 | 47,29.545,9.09727632125036,0,1,0,0,0,0,0,1,0,0 707 | 33,32.9,8.589520922738314,0,0,1,0,0,0,0,0,0,1 708 | 51,38.06,10.70100390153158,0,0,0,0,0,0,1,0,1,0 709 | 49,28.69,9.236440978243934,1,0,0,1,0,0,0,1,0,0 710 | 31,30.495,8.71821072581372,0,0,0,1,0,0,0,0,0,0 711 | 36,27.74,8.60685227014802,0,0,0,0,0,0,0,0,0,0 712 | 18,35.2,7.454453710221802,1,1,0,0,0,0,0,0,1,0 713 | 50,23.54,9.22100535829338,0,0,1,0,0,0,0,0,1,0 714 | 43,30.685,9.02531586349737,0,0,1,0,0,0,0,1,0,0 715 | 20,40.47,7.593098739570316,1,0,0,0,0,0,0,0,0,0 716 | 24,22.6,7.806900665856189,0,0,0,0,0,0,0,0,0,1 717 | 60,28.9,9.404835117276658,1,0,0,0,0,0,0,0,0,1 718 | 49,22.61,9.166074004491346,0,1,0,0,0,0,0,1,0,0 719 | 60,24.32,9.481329245046304,1,1,0,0,0,0,0,1,0,0 720 | 51,36.67,9.291748390265784,0,0,1,0,0,0,0,1,0,0 721 | 58,33.44,9.41177915783591,0,0,0,0,0,0,0,1,0,0 722 | 51,40.66,9.197830488661562,0,0,0,0,0,0,0,0,0,0 723 | 53,36.6,9.329415106363781,1,0,0,1,0,0,0,0,0,1 724 | 62,37.4,9.471115528326077,1,0,0,0,0,0,0,0,0,1 725 | 19,35.4,7.14144225256276,1,0,0,0,0,0,0,0,0,1 726 | 50,27.075,9.220897869951232,0,1,0,0,0,0,0,0,0,0 727 | 30,39.05,10.619677925164396,0,0,0,1,0,0,1,0,1,0 728 | 41,28.405,8.80457811222284,1,1,0,0,0,0,0,1,0,0 729 | 29,21.755,9.720628898531286,0,1,0,0,0,0,1,0,0,0 730 | 18,40.28,7.704181350120979,0,0,0,0,0,0,0,0,0,0 731 | 41,36.08,8.821932095503433,0,1,0,0,0,0,0,0,1,0 732 | 35,24.42,9.871067599302947,1,0,0,1,0,0,1,0,1,0 733 | 53,21.4,9.216860370515706,1,1,0,0,0,0,0,0,0,1 734 | 24,30.1,8.351121369629444,0,0,0,1,0,0,0,0,0,1 735 | 48,27.265,9.153479009894344,0,1,0,0,0,0,0,0,0,0 736 | 59,32.1,9.547328332731697,0,0,0,1,0,0,0,0,0,1 737 | 49,34.77,9.167839187154692,0,1,0,0,0,0,0,1,0,0 738 | 37,38.39,10.607055722973884,0,0,0,0,0,0,1,0,1,0 739 | 26,23.7,8.156031339200162,1,0,1,0,0,0,0,0,0,1 740 | 23,31.73,10.496513294475752,1,0,0,1,0,0,1,0,0,0 741 | 29,35.5,10.705162983255969,1,0,1,0,0,0,1,0,0,1 742 | 45,24.035,9.060038701034644,1,0,1,0,0,0,0,0,0,0 743 | 27,29.15,9.811728313173756,1,0,0,0,0,0,1,0,1,0 744 | 53,34.105,10.674854656276105,1,0,0,0,0,0,1,0,0,0 745 | 31,26.62,8.231600880557536,0,0,0,0,0,0,0,0,1,0 746 | 50,26.41,9.085594264050979,1,0,0,0,0,0,0,1,0,0 747 | 50,30.115,9.201335938471033,0,1,0,0,0,0,0,1,0,0 748 | 34,27.0,9.37057384320268,1,0,1,0,0,0,0,0,0,1 749 | 19,21.755,7.394666693872962,1,0,0,0,0,0,0,1,0,0 750 | 47,36.0,9.054494072064031,0,1,0,0,0,0,0,0,0,1 751 | 28,30.875,8.026989548726904,1,0,0,0,0,0,0,1,0,0 752 | 37,26.4,9.880180183802308,0,0,0,0,0,0,1,0,1,0 753 | 21,28.975,7.552950025628654,1,0,0,0,0,0,0,1,0,0 754 | 64,37.905,9.561738936776804,1,0,0,0,0,0,0,1,0,0 755 | 58,22.77,9.378713626920732,0,0,0,0,0,0,0,0,1,0 756 | 24,33.63,9.748494706186174,1,0,0,0,1,0,0,0,0,0 757 | 31,27.645,8.52342762687361,1,0,1,0,0,0,0,0,0,0 758 | 39,22.8,8.985422121815146,0,0,0,1,0,0,0,0,0,0 759 | 47,27.83,10.046089835582787,0,0,0,0,0,0,1,0,1,0 760 | 30,37.43,8.599460076080982,1,0,0,1,0,0,0,0,0,0 761 | 18,38.17,10.499787826381556,1,0,0,0,0,0,1,0,1,0 762 | 22,34.58,8.275314783535729,0,0,1,0,0,0,0,0,0,0 763 | 23,35.2,7.790263762408525,1,1,0,0,0,0,0,0,0,1 764 | 33,27.1,9.854343315690363,1,1,0,0,0,0,1,0,0,1 765 | 27,26.03,8.029696226087674,1,0,0,0,0,0,0,0,0,0 766 | 45,25.175,9.115487595047211,0,0,1,0,0,0,0,0,0,0 767 | 57,31.825,9.379460484394988,0,0,0,0,0,0,0,1,0,0 768 | 47,32.3,8.995011704753995,1,1,0,0,0,0,0,0,0,1 769 | 42,29.0,8.860873955490042,0,1,0,0,0,0,0,0,0,1 770 | 64,39.7,9.569344770627316,0,0,0,0,0,0,0,0,0,1 771 | 38,19.475,8.844082839915778,0,0,1,0,0,0,0,1,0,0 772 | 61,36.1,10.237860715500025,1,0,0,1,0,0,0,0,0,1 773 | 53,26.7,9.319264729598467,0,0,1,0,0,0,0,0,0,1 774 | 44,36.48,9.456982427705094,0,0,0,0,0,0,0,0,0,0 775 | 19,28.88,9.784056633615622,0,0,0,0,0,0,1,1,0,0 776 | 41,34.2,8.890374886232234,1,0,1,0,0,0,0,1,0,0 777 | 51,33.33,9.264875118676253,1,0,0,1,0,0,0,0,1,0 778 | 40,32.3,8.851763191360497,1,0,1,0,0,0,0,1,0,0 779 | 45,39.805,8.915755053522702,1,0,0,0,0,0,0,0,0,0 780 | 35,34.32,8.688517802847086,1,0,0,1,0,0,0,0,1,0 781 | 53,28.88,9.19723590225276,1,0,0,0,0,0,0,1,0,0 782 | 30,24.4,9.812425217849334,1,0,0,1,0,0,1,0,0,1 783 | 18,41.14,7.0447277692332815,1,0,0,0,0,0,0,0,1,0 784 | 51,35.97,9.1469916813761,1,1,0,0,0,0,0,0,1,0 785 | 50,27.6,10.107255156713231,0,1,0,0,0,0,1,0,0,1 786 | 31,29.26,8.378049369964973,0,1,0,0,0,0,0,0,1,0 787 | 35,27.7,8.766266131660979,0,0,0,1,0,0,0,0,0,1 788 | 60,36.955,9.452593561505488,1,0,0,0,0,0,0,0,0,0 789 | 21,36.86,7.558682822107171,1,0,0,0,0,0,0,1,0,0 790 | 29,22.515,8.558254296547272,1,0,0,1,0,0,0,0,0,0 791 | 62,29.92,9.50732609097838,0,0,0,0,0,0,0,0,1,0 792 | 39,41.8,8.641572203490552,0,0,0,0,0,0,0,0,1,0 793 | 19,27.6,7.132822578705235,1,0,0,0,0,0,0,0,0,1 794 | 22,23.18,7.912757082546145,0,0,0,0,0,0,0,0,0,0 795 | 53,20.9,9.96155917705003,1,0,0,0,0,0,1,0,1,0 796 | 39,31.92,8.883153742357887,0,0,1,0,0,0,0,1,0,0 797 | 27,28.5,9.815243161151129,1,0,0,0,0,0,1,1,0,0 798 | 30,44.22,8.35847076372378,1,0,1,0,0,0,0,0,1,0 799 | 30,22.895,8.459463236630816,0,1,0,0,0,0,0,0,0,0 800 | 58,33.1,9.379926256619562,0,0,0,0,0,0,0,0,0,1 801 | 33,24.795,9.792808867674283,1,0,0,0,0,0,1,0,0,0 802 | 42,26.18,8.860317851519767,0,1,0,0,0,0,0,0,1,0 803 | 64,35.97,9.568982620501616,0,0,0,0,0,0,0,0,1,0 804 | 21,22.3,7.651158215873124,1,1,0,0,0,0,0,0,0,1 805 | 18,42.24,10.565986992376173,0,0,0,0,0,0,1,0,1,0 806 | 23,26.51,7.504323219821754,1,0,0,0,0,0,0,0,1,0 807 | 45,35.815,8.95310445552394,0,0,0,0,0,0,0,1,0,0 808 | 40,41.42,10.256842716748936,0,1,0,0,0,0,0,1,0,0 809 | 19,36.575,7.667103153192724,0,0,0,0,0,0,0,1,0,0 810 | 18,30.14,7.031305298021671,1,0,0,0,0,0,0,0,1,0 811 | 25,25.84,8.104640807797704,1,1,0,0,0,0,0,0,0,0 812 | 46,30.8,9.150050943976023,0,0,0,1,0,0,0,0,0,1 813 | 33,42.94,8.757939870547187,0,0,0,1,0,0,0,1,0,0 814 | 54,21.01,9.306896311862733,1,0,1,0,0,0,0,0,1,0 815 | 28,22.515,8.395903781859541,1,0,1,0,0,0,0,0,0,0 816 | 36,34.43,8.627715388645722,1,0,1,0,0,0,0,0,1,0 817 | 20,31.46,7.537925065877328,0,0,0,0,0,0,0,0,1,0 818 | 24,24.225,7.952530954047238,0,0,0,0,0,0,0,1,0,0 819 | 23,37.1,8.188021123603534,1,0,0,1,0,0,0,0,0,1 820 | 47,26.125,10.06054710107101,0,1,0,0,0,0,1,0,0,0 821 | 33,35.53,10.917547294992884,0,0,0,0,0,0,1,1,0,0 822 | 45,33.7,8.915421241747795,1,1,0,0,0,0,0,0,0,1 823 | 26,17.67,7.893926227202988,1,0,0,0,0,0,0,1,0,0 824 | 18,31.13,7.391342913934506,0,0,0,0,0,0,0,0,1,0 825 | 44,29.81,9.014228634211625,0,0,1,0,0,0,0,0,1,0 826 | 60,24.32,9.435370526534808,1,0,0,0,0,0,0,1,0,0 827 | 64,31.825,9.684652503158159,0,0,1,0,0,0,0,0,0,0 828 | 56,31.79,10.687705623889984,1,0,1,0,0,0,1,0,1,0 829 | 36,28.025,9.941439564593802,1,1,0,0,0,0,1,0,0,0 830 | 41,30.78,10.586518920351532,1,0,0,1,0,0,1,0,0,0 831 | 39,21.85,8.718907896256349,1,1,0,0,0,0,0,1,0,0 832 | 63,33.1,9.502543907191923,1,0,0,0,0,0,0,0,0,1 833 | 36,25.84,8.569095764156032,0,0,0,0,0,0,0,1,0,0 834 | 28,23.845,8.459508261343881,0,0,1,0,0,0,0,1,0,0 835 | 58,34.39,9.371092139462531,1,0,0,0,0,0,0,1,0,0 836 | 36,33.82,8.589971013598309,1,1,0,0,0,0,0,1,0,0 837 | 42,35.97,8.876311390175593,1,0,1,0,0,0,0,0,1,0 838 | 36,31.5,8.389867191171781,1,0,0,0,0,0,0,0,0,1 839 | 56,28.31,9.363723806117159,0,0,0,0,0,0,0,0,0,0 840 | 35,23.465,8.764411228710166,0,0,1,0,0,0,0,0,0,0 841 | 59,31.35,9.443210823244142,0,0,0,0,0,0,0,1,0,0 842 | 21,31.1,7.330609647040468,1,0,0,0,0,0,0,0,0,1 843 | 59,24.7,9.419298666583957,1,0,0,0,0,0,0,0,0,0 844 | 23,32.78,10.491857691628514,0,0,1,0,0,0,1,0,1,0 845 | 57,29.81,10.223173720256224,0,0,0,0,0,0,1,0,1,0 846 | 53,30.495,9.217520041356586,1,0,0,0,0,0,0,0,0,0 847 | 60,32.45,10.714616760063484,0,0,0,0,0,0,1,0,1,0 848 | 51,34.2,9.197528752538256,0,1,0,0,0,0,0,0,0,1 849 | 23,50.38,7.798955951294335,1,1,0,0,0,0,0,0,1,0 850 | 27,24.1,7.997705493304883,0,0,0,0,0,0,0,0,0,1 851 | 55,32.775,9.268763254094612,1,0,0,0,0,0,0,1,0,0 852 | 37,30.78,10.525948049347285,0,0,0,0,0,0,1,0,0,0 853 | 61,32.3,9.55532059850379,1,0,1,0,0,0,0,1,0,0 854 | 46,35.53,10.648080052552228,0,0,0,0,0,0,1,0,0,0 855 | 53,23.75,9.369877618171085,0,0,1,0,0,0,0,0,0,0 856 | 49,23.845,10.090253906152347,0,0,0,1,0,0,1,0,0,0 857 | 20,29.6,7.5365473882432275,0,0,0,0,0,0,0,0,0,1 858 | 48,33.11,10.62069702268439,0,0,0,0,0,0,1,0,1,0 859 | 25,24.13,9.668902907045574,1,0,0,0,0,0,1,1,0,0 860 | 25,32.23,9.810174254086462,0,1,0,0,0,0,0,0,1,0 861 | 57,28.1,9.302504334899389,1,0,0,0,0,0,0,0,0,1 862 | 37,47.6,10.738861266305413,0,0,1,0,0,0,1,0,0,1 863 | 38,28.0,8.875020351299158,0,0,0,1,0,0,0,0,0,1 864 | 55,33.535,9.414887162484883,0,0,1,0,0,0,0,1,0,0 865 | 36,19.855,8.604846211675456,0,0,0,0,0,0,0,0,0,0 866 | 51,25.4,9.080512854387097,1,0,0,0,0,0,0,0,0,1 867 | 40,29.9,8.79487962348839,1,0,1,0,0,0,0,0,0,1 868 | 18,37.29,7.040050370200915,1,0,0,0,0,0,0,0,1,0 869 | 57,43.7,9.356700498379569,1,1,0,0,0,0,0,0,0,1 870 | 61,23.655,9.482624765012883,1,0,0,0,0,0,0,0,0,0 871 | 25,24.3,8.387460745077433,0,0,0,1,0,0,0,0,0,1 872 | 50,36.2,9.042846499711533,1,0,0,0,0,0,0,0,0,1 873 | 26,29.48,8.129282656210663,0,1,0,0,0,0,0,0,1,0 874 | 42,24.86,8.693980696889868,1,0,0,0,0,0,0,0,1,0 875 | 43,30.1,8.831861731365324,1,1,0,0,0,0,0,0,0,1 876 | 44,21.85,9.092810498021672,1,0,0,1,0,0,0,0,0,0 877 | 23,28.12,7.897338776533775,0,0,0,0,0,0,0,1,0,0 878 | 49,27.1,10.171235770556825,0,1,0,0,0,0,0,0,0,1 879 | 33,33.44,8.802941685710042,1,0,0,0,0,1,0,0,1,0 880 | 41,28.8,8.745481087867553,1,1,0,0,0,0,0,0,0,1 881 | 37,29.5,8.750200257934058,0,0,1,0,0,0,0,0,0,1 882 | 22,34.8,8.144117051606075,1,0,0,1,0,0,0,0,0,1 883 | 23,27.36,7.933458968269059,1,1,0,0,0,0,0,1,0,0 884 | 21,22.135,7.857809804377088,0,0,0,0,0,0,0,0,0,0 885 | 51,37.05,10.741927277371957,0,0,0,1,0,0,1,0,0,0 886 | 25,26.695,8.492486693979473,1,0,0,0,1,0,0,1,0,0 887 | 32,28.93,9.88937314629236,1,1,0,0,0,0,1,0,1,0 888 | 57,28.975,10.211649862727798,1,0,0,0,0,0,1,0,0,0 889 | 36,30.02,8.570198421605134,0,0,0,0,0,0,0,1,0,0 890 | 22,39.5,7.428093712160173,1,0,0,0,0,0,0,0,0,1 891 | 57,33.63,9.388079168948936,1,1,0,0,0,0,0,1,0,0 892 | 64,26.885,10.2863996816961,0,0,0,0,0,0,1,1,0,0 893 | 36,29.04,8.887903087032262,0,0,0,0,1,0,0,0,1,0 894 | 54,24.035,9.251762184969365,1,0,0,0,0,0,0,0,0,0 895 | 47,38.94,10.696540102462784,1,0,1,0,0,0,1,0,1,0 896 | 62,32.11,9.514511123422926,1,0,0,0,0,0,0,0,0,0 897 | 61,44.0,9.477606678700827,0,0,0,0,0,0,0,0,0,1 898 | 43,20.045,9.893338956804778,0,0,1,0,0,0,1,0,0,0 899 | 19,25.555,7.705966933884002,1,1,0,0,0,0,0,1,0,0 900 | 18,40.26,7.399137131855286,0,0,0,0,0,0,0,0,1,0 901 | 19,22.515,7.657915319734057,0,0,0,0,0,0,0,1,0,0 902 | 49,22.515,9.069796892030082,1,0,0,0,0,0,0,0,0,0 903 | 60,40.92,10.792891221173397,1,0,0,0,0,0,1,0,1,0 904 | 26,27.265,8.447046729799979,1,0,0,1,0,0,0,0,0,0 905 | 49,36.85,9.002797556383069,1,0,0,0,0,0,0,0,1,0 906 | 60,35.1,9.444984655610234,0,0,0,0,0,0,0,0,0,1 907 | 26,29.355,8.42599665795494,0,0,1,0,0,0,0,0,0,0 908 | 27,32.585,8.486098761601982,1,0,0,1,0,0,0,0,0,0 909 | 44,32.34,8.940330633211769,0,1,0,0,0,0,0,0,1,0 910 | 63,39.8,9.627079620783123,1,0,0,1,0,0,0,0,0,1 911 | 32,24.6,9.769745051915594,0,0,0,0,0,0,1,0,0,1 912 | 22,28.31,7.87817159252883,1,1,0,0,0,0,0,1,0,0 913 | 18,31.73,10.426222578011334,1,0,0,0,0,0,1,0,0,0 914 | 59,26.695,9.573782003657021,0,0,0,1,0,0,0,1,0,0 915 | 44,27.5,8.939448944371764,0,1,0,0,0,0,0,0,0,1 916 | 33,24.605,8.567412419701247,1,0,1,0,0,0,0,1,0,0 917 | 24,33.99,7.813322357466315,0,0,0,0,0,0,0,0,1,0 918 | 43,26.885,9.988486671500228,0,0,0,0,0,0,1,1,0,0 919 | 45,22.895,10.465083507788405,1,0,0,0,0,0,1,0,0,0 920 | 61,28.2,9.475924140581634,0,0,0,0,0,0,0,0,0,1 921 | 35,34.21,8.565073780142555,0,1,0,0,0,0,0,0,1,0 922 | 62,25.0,9.506817801625074,0,0,0,0,0,0,0,0,0,1 923 | 62,33.2,9.507664807071711,0,0,0,0,0,0,0,0,0,1 924 | 38,31.0,8.61036690879096,1,1,0,0,0,0,0,0,0,1 925 | 34,35.815,8.371105780882708,1,0,0,0,0,0,0,1,0,0 926 | 43,23.2,8.74040634030848,1,0,0,0,0,0,0,0,0,1 927 | 50,32.11,10.139876311126674,1,0,1,0,0,0,0,0,0,0 928 | 19,23.4,7.9771340691583665,0,0,1,0,0,0,0,0,0,1 929 | 57,20.1,9.395352140237467,0,1,0,0,0,0,0,0,0,1 930 | 62,39.16,9.508279985512978,0,0,0,0,0,0,0,0,1,0 931 | 41,34.21,8.746677382321595,1,1,0,0,0,0,0,0,1,0 932 | 26,46.53,7.981755390991486,1,1,0,0,0,0,0,0,1,0 933 | 39,32.5,8.738462667748422,0,1,0,0,0,0,0,0,0,1 934 | 46,25.8,9.219990657820349,1,0,0,0,0,1,0,0,0,1 935 | 45,35.3,8.902202771134682,0,0,0,0,0,0,0,0,0,1 936 | 32,37.18,8.449640468132152,1,0,1,0,0,0,0,0,1,0 937 | 59,27.5,9.411960180524343,0,0,0,0,0,0,0,0,0,1 938 | 44,29.735,10.376881142491738,1,0,1,0,0,0,0,0,0,0 939 | 39,24.225,9.101172143951779,0,0,0,0,0,1,0,1,0,0 940 | 18,26.18,7.742402976676437,1,0,1,0,0,0,0,0,1,0 941 | 53,29.48,9.157745620534364,1,0,0,0,0,0,0,0,1,0 942 | 18,23.21,7.02275569117477,1,0,0,0,0,0,0,0,1,0 943 | 50,46.09,9.164250893170816,0,1,0,0,0,0,0,0,1,0 944 | 18,40.185,7.704121802023827,0,0,0,0,0,0,0,0,0,0 945 | 19,22.61,7.395396755351842,1,0,0,0,0,0,0,1,0,0 946 | 62,39.93,9.471386437231496,1,0,0,0,0,0,0,0,1,0 947 | 56,35.8,9.365130561559194,0,1,0,0,0,0,0,0,0,1 948 | 42,35.8,8.876278388360134,1,0,1,0,0,0,0,0,0,1 949 | 37,34.2,10.57252862660237,1,1,0,0,0,0,1,0,0,0 950 | 42,31.255,8.75759125575089,1,0,0,0,0,0,0,1,0,0 951 | 25,29.7,9.900154905431657,1,0,0,1,0,0,1,0,0,1 952 | 57,18.335,9.353130130234815,1,0,0,0,0,0,0,0,0,0 953 | 51,42.9,10.767703505796094,1,0,1,0,0,0,1,0,1,0 954 | 30,28.405,8.417855159696465,0,1,0,0,0,0,0,1,0,0 955 | 44,30.2,10.571279642365509,1,0,1,0,0,0,1,0,0,1 956 | 34,27.835,9.903969119064353,1,1,0,0,0,0,1,1,0,0 957 | 31,39.49,8.262490369006269,1,1,0,0,0,0,0,0,1,0 958 | 54,30.8,10.645413468628771,1,1,0,0,0,0,1,0,1,0 959 | 24,26.79,9.44223646936292,1,1,0,0,0,0,0,1,0,0 960 | 43,34.96,10.622161665837258,1,1,0,0,0,0,1,0,0,0 961 | 48,36.67,10.256568210109709,1,1,0,0,0,0,0,1,0,0 962 | 19,39.615,7.912096392893189,0,1,0,0,0,0,0,1,0,0 963 | 29,25.9,8.11769544314778,0,0,0,0,0,0,0,0,0,1 964 | 63,35.2,9.580155849684816,0,1,0,0,0,0,0,0,1,0 965 | 46,24.795,9.159107396822023,1,0,0,1,0,0,0,0,0,0 966 | 52,36.765,10.183657631860399,1,0,1,0,0,0,0,1,0,0 967 | 35,27.1,8.46512991645919,1,1,0,0,0,0,0,0,0,1 968 | 51,24.795,10.08444914541489,1,0,1,0,0,0,1,1,0,0 969 | 44,25.365,8.92505879602586,1,1,0,0,0,0,0,1,0,0 970 | 21,25.745,8.095558624355604,1,0,1,0,0,0,0,0,0,0 971 | 39,34.32,9.059148553730727,0,0,0,0,0,1,0,0,1,0 972 | 50,28.16,9.278245943233086,0,0,0,1,0,0,0,0,1,0 973 | 34,23.56,8.515667307847805,0,0,0,0,0,0,0,0,0,0 974 | 22,20.235,7.835112016142926,0,0,0,0,0,0,0,1,0,0 975 | 19,40.5,7.472692880911536,0,0,0,0,0,0,0,0,0,1 976 | 26,35.42,7.750451912800503,1,0,0,0,0,0,0,0,1,0 977 | 29,22.895,9.688979238138792,1,0,0,0,0,0,1,0,0,0 978 | 48,40.15,8.962412267907734,1,0,0,0,0,0,0,0,1,0 979 | 26,29.15,7.973467755445312,1,1,0,0,0,0,0,0,1,0 980 | 45,39.995,9.180362290999593,0,0,0,1,0,0,0,0,0,0 981 | 36,29.92,8.494750589651973,0,0,0,0,0,0,0,0,1,0 982 | 54,25.46,10.147104628789455,1,1,0,0,0,0,0,0,0,0 983 | 34,21.375,8.4119080618057,1,0,0,0,0,0,0,0,0,0 984 | 31,25.9,9.862662641344953,1,0,0,1,0,0,1,0,0,1 985 | 27,30.59,9.728920567580962,0,1,0,0,0,0,0,0,0,0 986 | 20,30.115,8.500059209516284,1,0,0,0,0,1,0,0,0,0 987 | 44,25.8,8.939139075708093,0,1,0,0,0,0,0,0,0,1 988 | 43,30.115,9.037182323700586,1,0,0,1,0,0,0,1,0,0 989 | 45,27.645,10.252036176948652,0,1,0,0,0,0,0,1,0,0 990 | 34,34.675,8.416007559900255,1,0,0,0,0,0,0,0,0,0 991 | 24,20.52,9.586849664276604,0,0,0,0,0,0,1,0,0,0 992 | 26,19.8,8.125308451260427,0,1,0,0,0,0,0,0,0,1 993 | 38,27.835,8.874148866946168,0,0,1,0,0,0,0,0,0,0 994 | 50,31.6,9.222113199488794,0,0,1,0,0,0,0,0,0,1 995 | 38,28.27,8.609675248576345,1,1,0,0,0,0,0,0,1,0 996 | 27,20.045,9.706285501310472,0,0,0,1,0,0,1,1,0,0 997 | 39,23.275,8.985504796245682,0,0,0,1,0,0,0,0,0,0 998 | 39,34.1,8.911735124945526,0,0,0,1,0,0,0,0,0,1 999 | 63,36.85,9.538778168752398,0,0,0,0,0,0,0,0,1,0 1000 | 33,36.29,8.787487483779877,0,0,0,1,0,0,0,0,0,0 1001 | 36,26.885,8.569371542525515,0,0,0,0,0,0,0,1,0,0 1002 | 30,22.99,9.76202571691077,1,0,1,0,0,0,1,1,0,0 1003 | 24,32.7,10.447927075609824,1,0,0,0,0,0,1,0,0,1 1004 | 24,25.8,7.587285163582897,1,0,0,0,0,0,0,0,0,1 1005 | 48,29.6,9.963273340747653,1,0,0,0,0,0,0,0,0,1 1006 | 47,19.19,9.06271481879738,1,1,0,0,0,0,0,0,0,0 1007 | 29,31.73,8.396919288624439,1,0,1,0,0,0,0,1,0,0 1008 | 28,29.26,8.398018452790371,1,0,1,0,0,0,0,0,0,0 1009 | 47,28.215,10.123234174814288,1,0,0,1,0,0,1,1,0,0 1010 | 25,24.985,10.053693656887708,1,0,1,0,0,0,0,0,0,0 1011 | 51,27.74,9.206103569390143,1,1,0,0,0,0,0,0,0,0 1012 | 48,22.8,9.020274182786737,0,0,0,0,0,0,0,0,0,1 1013 | 43,20.13,9.839894594879139,1,0,1,0,0,0,1,0,1,0 1014 | 61,33.33,10.507264635419755,0,0,0,0,1,0,0,0,1,0 1015 | 48,32.3,9.078550205394492,1,1,0,0,0,0,0,1,0,0 1016 | 38,27.6,8.591100686332883,0,0,0,0,0,0,0,0,0,1 1017 | 59,25.46,9.403024089001363,1,0,0,0,0,0,0,1,0,0 1018 | 19,24.605,7.904424889710272,0,1,0,0,0,0,0,1,0,0 1019 | 26,34.2,8.291026575242569,0,0,1,0,0,0,0,0,0,1 1020 | 54,35.815,9.433107120309066,0,0,0,1,0,0,0,1,0,0 1021 | 21,32.68,10.166580417663528,0,0,1,0,0,0,0,1,0,0 1022 | 51,37.0,9.082347101319474,1,0,0,0,0,0,0,0,0,1 1023 | 22,31.02,10.479977027143638,0,0,0,1,0,0,1,0,1,0 1024 | 47,36.08,10.65043940358712,1,1,0,0,0,0,1,0,1,0 1025 | 18,23.32,7.444848937124288,1,1,0,0,0,0,0,0,1,0 1026 | 47,45.32,9.056006885440796,0,1,0,0,0,0,0,0,1,0 1027 | 21,34.6,7.610940410318889,0,0,0,0,0,0,0,0,0,1 1028 | 19,26.03,9.708135143772237,1,1,0,0,0,0,1,1,0,0 1029 | 23,18.715,9.98023478794707,1,0,0,0,0,0,0,1,0,0 1030 | 54,31.6,9.195270591072427,1,0,0,0,0,0,0,0,0,1 1031 | 37,17.29,8.836080297705095,0,0,1,0,0,0,0,0,0,0 1032 | 46,23.655,9.984020145580844,0,1,0,0,0,0,1,1,0,0 1033 | 55,35.2,10.701530708371722,0,0,0,0,0,0,1,0,1,0 1034 | 30,27.93,8.327852506075102,0,0,0,0,0,0,0,0,0,0 1035 | 18,21.565,9.528639352939711,1,0,0,0,0,0,1,0,0,0 1036 | 61,38.38,9.468856565182067,1,0,0,0,0,0,0,1,0,0 1037 | 54,23.0,9.400504263782892,0,0,0,1,0,0,0,0,0,1 1038 | 22,37.07,10.531681440619428,1,0,1,0,0,0,1,0,1,0 1039 | 45,30.495,10.589749032226115,0,1,0,0,0,0,1,1,0,0 1040 | 22,28.88,7.71905662632079,1,0,0,0,0,0,0,0,0,0 1041 | 19,27.265,10.020988754703406,1,0,1,0,0,0,0,1,0,0 1042 | 35,28.025,9.915161879127544,0,0,0,0,0,0,1,1,0,0 1043 | 18,23.085,7.441144509148898,1,0,0,0,0,0,0,0,0,0 1044 | 20,30.685,10.41857858101573,1,0,0,0,0,0,1,0,0,0 1045 | 28,25.8,8.05878732733746,0,0,0,0,0,0,0,0,0,1 1046 | 55,35.245,9.340847933051702,1,1,0,0,0,0,0,0,0,0 1047 | 43,24.7,9.993365732981747,0,0,1,0,0,0,1,1,0,0 1048 | 43,25.08,8.899055014068397,0,0,0,0,0,0,0,0,0,0 1049 | 22,52.58,10.703275887885447,1,1,0,0,0,0,1,0,1,0 1050 | 25,22.515,8.187068603776234,0,1,0,0,0,0,0,1,0,0 1051 | 49,30.9,10.589801791631476,1,0,0,0,0,0,1,0,0,1 1052 | 44,36.955,8.990084578323348,0,1,0,0,0,0,0,1,0,0 1053 | 64,26.41,9.574605490521856,1,0,0,0,0,0,0,0,0,0 1054 | 49,29.83,9.136481398050599,1,1,0,0,0,0,0,0,0,0 1055 | 47,29.8,10.138934663686996,1,0,0,1,0,0,1,0,0,1 1056 | 27,21.47,8.117750999081906,0,0,0,0,0,0,0,1,0,0 1057 | 55,27.645,9.268090423819404,1,0,0,0,0,0,0,1,0,0 1058 | 48,28.9,9.021299048034273,0,0,0,0,0,0,0,0,0,1 1059 | 45,31.79,9.794191713083654,0,0,0,0,0,0,0,0,1,0 1060 | 24,39.49,7.816408559633747,0,0,0,0,0,0,0,0,1,0 1061 | 32,33.82,8.40351412793397,1,1,0,0,0,0,0,1,0,0 1062 | 24,32.01,7.591650744100329,1,0,0,0,0,0,0,0,1,0 1063 | 57,27.94,9.35480632875911,1,1,0,0,0,0,0,0,1,0 1064 | 59,41.14,10.798968200840411,1,1,0,0,0,0,1,0,1,0 1065 | 36,28.595,8.786944725768821,1,0,0,1,0,0,0,1,0,0 1066 | 29,25.6,8.649775859143583,0,0,0,0,1,0,0,0,0,1 1067 | 42,25.3,8.86014425220058,0,1,0,0,0,0,0,0,0,1 1068 | 48,37.29,9.102553036193283,1,0,1,0,0,0,0,0,1,0 1069 | 39,42.655,8.658243599015632,1,0,0,0,0,0,0,0,0,0 1070 | 63,21.66,9.571495074794829,1,1,0,0,0,0,0,1,0,0 1071 | 54,31.9,9.299161269129582,0,1,0,0,0,0,0,0,1,0 1072 | 37,37.07,10.593422185887682,1,1,0,0,0,0,1,0,1,0 1073 | 63,31.445,9.544986338409286,1,0,0,0,0,0,0,0,0,0 1074 | 21,31.255,7.554611082053211,1,0,0,0,0,0,0,1,0,0 1075 | 54,28.88,9.400683932949047,0,0,1,0,0,0,0,0,0,0 1076 | 60,18.335,9.48829672633496,0,0,0,0,0,0,0,0,0,0 1077 | 32,29.59,8.425700975901744,0,1,0,0,0,0,0,0,1,0 1078 | 47,32.0,9.053844093381725,0,1,0,0,0,0,0,0,0,1 1079 | 21,26.03,7.650770471196587,1,0,0,0,0,0,0,0,0,0 1080 | 28,31.68,10.45369196926782,1,0,0,0,0,0,1,0,1,0 1081 | 63,33.66,9.626516867794916,1,0,0,1,0,0,0,0,1,0 1082 | 18,21.78,9.382952324423352,1,0,1,0,0,0,0,0,1,0 1083 | 32,27.835,8.401648245617254,1,1,0,0,0,0,0,1,0,0 1084 | 38,19.95,8.675205405912378,1,1,0,0,0,0,0,1,0,0 1085 | 32,31.5,8.312993320177268,1,1,0,0,0,0,0,0,0,1 1086 | 62,30.495,9.61712194982434,0,0,1,0,0,0,0,1,0,0 1087 | 39,18.3,9.853417719940197,0,0,0,0,0,1,1,0,0,1 1088 | 55,28.975,9.286963416182969,1,0,0,0,0,0,0,0,0,0 1089 | 57,31.54,9.337257352528104,1,0,0,0,0,0,0,1,0,0 1090 | 52,47.74,9.184910824415926,1,1,0,0,0,0,0,0,1,0 1091 | 56,22.1,9.26644533668895,1,0,0,0,0,0,0,0,0,1 1092 | 47,36.19,10.637682648494286,1,0,0,0,0,0,1,0,1,0 1093 | 55,29.83,9.331366029092958,0,0,0,0,0,0,0,0,0,0 1094 | 23,32.7,8.186319652795467,1,0,0,1,0,0,0,0,0,1 1095 | 22,30.4,10.431392923451883,0,0,0,0,0,0,1,1,0,0 1096 | 50,33.7,9.332499861417224,0,0,0,0,1,0,0,0,0,1 1097 | 18,31.35,8.425338504513691,0,0,0,0,1,0,0,0,0,0 1098 | 51,34.96,10.706412420172152,0,0,1,0,0,0,1,0,0,0 1099 | 22,33.77,7.423348897772541,1,0,0,0,0,0,0,0,1,0 1100 | 52,30.875,10.04522867243799,0,0,0,0,0,0,0,0,0,0 1101 | 25,33.99,8.079345718462804,0,1,0,0,0,0,0,0,1,0 1102 | 33,19.095,9.727722696523381,0,0,1,0,0,0,1,0,0,0 1103 | 53,28.6,9.3284274502958,1,0,0,1,0,0,0,0,0,1 1104 | 29,38.94,8.152316015237817,1,1,0,0,0,0,0,0,1,0 1105 | 58,36.08,9.338142664603124,1,0,0,0,0,0,0,0,1,0 1106 | 37,29.8,9.924299701956077,1,0,0,0,0,0,0,0,0,1 1107 | 54,31.24,9.24367181583795,0,0,0,0,0,0,0,0,1,0 1108 | 49,29.925,9.103663295588047,0,0,0,0,0,0,0,1,0,0 1109 | 50,26.22,9.25855377937721,0,0,1,0,0,0,0,1,0,0 1110 | 26,30.0,7.9738746785158625,1,1,0,0,0,0,0,0,0,1 1111 | 45,20.35,9.06014071822226,1,0,0,1,0,0,0,0,1,0 1112 | 54,32.3,9.351180428629407,0,1,0,0,0,0,0,0,0,0 1113 | 38,38.39,10.644215692662685,1,0,0,1,0,0,1,0,1,0 1114 | 48,25.85,10.093319729709767,0,0,0,1,0,0,1,0,1,0 1115 | 28,26.315,8.577755665419184,0,0,0,1,0,0,0,1,0,0 1116 | 23,24.51,7.7815959834760955,1,0,0,0,0,0,0,0,0,0 1117 | 55,32.67,9.28799434890277,1,1,0,0,0,0,0,0,1,0 1118 | 41,29.64,9.129390868287384,1,0,0,0,0,1,0,0,0,0 1119 | 25,33.33,10.494728624653064,1,0,1,0,0,0,1,0,1,0 1120 | 33,35.75,10.552754669006335,1,1,0,0,0,0,1,0,1,0 1121 | 30,19.95,8.647068245273546,0,0,0,1,0,0,0,1,0,0 1122 | 23,31.4,10.438994266874893,0,0,0,0,0,0,1,0,0,1 1123 | 46,38.17,9.029677155375715,1,0,1,0,0,0,0,0,1,0 1124 | 53,36.86,10.750673458085194,0,0,0,1,0,0,1,1,0,0 1125 | 27,32.395,9.847101914674951,0,1,0,0,0,0,0,0,0,0 1126 | 23,42.75,10.618988014021557,0,1,0,0,0,0,1,0,0,0 1127 | 63,25.08,9.5648355158761,0,0,0,0,0,0,0,1,0,0 1128 | 55,29.9,9.231576872745064,1,0,0,0,0,0,0,0,0,1 1129 | 35,35.86,8.671890076332048,0,0,1,0,0,0,0,0,1,0 1130 | 34,32.8,9.572087934304326,1,1,0,0,0,0,0,0,0,1 1131 | 19,18.6,7.455238911901867,0,0,0,0,0,0,0,0,0,1 1132 | 39,23.87,9.057457489820392,0,0,0,0,0,1,0,0,1,0 1133 | 27,45.9,8.21431030307363,1,0,1,0,0,0,0,0,0,1 1134 | 57,40.28,9.938324649552763,1,0,0,0,0,0,0,0,0,0 1135 | 52,18.335,9.209443735117471,0,0,0,0,0,0,0,1,0,0 1136 | 28,33.82,9.887019481651924,1,0,0,0,0,0,0,1,0,0 1137 | 50,28.12,9.313401057049871,0,0,0,1,0,0,0,1,0,0 1138 | 44,25.0,8.938993221929394,0,1,0,0,0,0,0,0,0,1 1139 | 26,22.23,8.063468403906713,0,0,0,0,0,0,0,1,0,0 1140 | 33,30.25,8.217264298529827,1,0,0,0,0,0,0,0,1,0 1141 | 19,32.49,10.51593249556386,0,0,0,0,0,0,1,1,0,0 1142 | 50,37.07,9.110302035032785,1,1,0,0,0,0,0,0,1,0 1143 | 41,32.6,8.98149522239808,0,0,0,1,0,0,0,0,0,1 1144 | 52,24.86,10.20795276365428,0,0,0,0,0,0,0,0,1,0 1145 | 39,32.34,8.754330468232741,1,0,1,0,0,0,0,0,1,0 1146 | 50,32.3,9.172679729279917,1,0,1,0,0,0,0,0,0,1 1147 | 52,32.775,9.331593756776948,1,0,0,1,0,0,0,1,0,0 1148 | 60,32.8,10.870297037328017,1,0,0,0,0,0,1,0,0,1 1149 | 20,31.92,7.7238140107412425,0,0,0,0,0,0,0,1,0,0 1150 | 55,21.5,9.286556691431501,1,1,0,0,0,0,0,0,0,1 1151 | 42,34.1,8.696130862655307,1,0,0,0,0,0,0,0,0,1 1152 | 18,30.305,7.697909358195443,0,0,0,0,0,0,0,0,0,0 1153 | 58,36.48,9.412124563634917,0,0,0,0,0,0,0,1,0,0 1154 | 43,32.56,10.619894255888985,0,0,0,1,0,0,1,0,1,0 1155 | 35,35.815,8.635946041095384,0,1,0,0,0,0,0,1,0,0 1156 | 48,27.93,9.30702911930132,0,0,0,0,1,0,0,1,0,0 1157 | 36,22.135,8.885747486629533,0,0,0,1,0,0,0,0,0,0 1158 | 19,44.88,10.58967925474193,1,0,0,0,0,0,1,0,1,0 1159 | 23,23.18,9.576792532279685,0,0,1,0,0,0,0,1,0,0 1160 | 20,30.59,7.807802841965112,0,0,0,0,0,0,0,0,0,0 1161 | 32,41.1,8.291506659465831,0,0,0,0,0,0,0,0,0,1 1162 | 43,34.58,8.952508735612067,0,1,0,0,0,0,0,1,0,0 1163 | 34,42.13,8.54172748903643,1,0,1,0,0,0,0,0,1,0 1164 | 30,38.83,9.850254057175354,1,1,0,0,0,0,0,0,1,0 1165 | 18,28.215,7.696590227142071,0,0,0,0,0,0,0,0,0,0 1166 | 41,28.31,8.87536456115119,0,1,0,0,0,0,0,1,0,0 1167 | 35,26.125,8.561781922867276,0,0,0,0,0,0,0,0,0,0 1168 | 57,40.37,9.304058494220062,1,0,0,0,0,0,0,0,1,0 1169 | 29,24.6,8.41836175927329,0,0,1,0,0,0,0,0,0,1 1170 | 32,35.2,8.449051386241019,1,0,1,0,0,0,0,0,0,1 1171 | 37,34.105,8.718067076234034,0,1,0,0,0,0,0,1,0,0 1172 | 18,27.36,9.75142449876709,1,1,0,0,0,0,1,0,0,0 1173 | 43,26.7,10.020319024488227,0,0,1,0,0,0,1,0,0,1 1174 | 56,41.91,9.314125708690787,0,0,0,0,0,0,0,0,1,0 1175 | 38,29.26,8.773050702030712,1,0,1,0,0,0,0,1,0,0 1176 | 29,32.11,8.397038422923758,1,0,1,0,0,0,0,1,0,0 1177 | 22,27.1,7.675249438845605,0,0,0,0,0,0,0,0,0,1 1178 | 52,24.13,10.081117399619002,0,1,0,0,0,0,1,1,0,0 1179 | 40,27.4,8.779078264166637,0,1,0,0,0,0,0,0,0,1 1180 | 23,34.865,7.972289914262673,0,0,0,0,0,0,0,0,0,0 1181 | 31,29.81,9.870466762875685,1,0,0,0,0,0,1,0,1,0 1182 | 42,41.325,8.942562065496743,0,1,0,0,0,0,0,0,0,0 1183 | 24,29.925,7.955314156769049,0,0,0,0,0,0,0,1,0,0 1184 | 25,30.3,7.875876121132408,0,0,0,0,0,0,0,0,0,1 1185 | 48,27.36,9.153492987408674,0,1,0,0,0,0,0,0,0,0 1186 | 23,28.49,9.81619821510089,0,1,0,0,0,0,1,0,1,0 1187 | 45,23.56,9.059961964839921,1,0,1,0,0,0,0,0,0,0 1188 | 20,35.625,10.531171617986534,1,0,0,1,0,0,1,1,0,0 1189 | 62,32.68,9.535664787610457,0,0,0,0,0,0,0,1,0,0 1190 | 43,25.27,9.988349810573093,0,1,0,0,0,0,1,0,0,0 1191 | 23,28.0,9.482401885007656,0,0,0,0,0,0,0,0,0,1 1192 | 31,32.775,8.580618640193542,0,0,1,0,0,0,0,1,0,0 1193 | 41,21.755,9.527008643928893,0,1,0,0,0,0,0,0,0,0 1194 | 58,32.395,9.474177478202634,0,1,0,0,0,0,0,0,0,0 1195 | 48,36.575,9.067761459413477,0,0,0,0,0,0,0,1,0,0 1196 | 31,21.755,8.327020684406639,0,0,0,0,0,0,0,1,0,0 1197 | 19,27.93,9.84366873790736,0,0,0,1,0,0,0,1,0,0 1198 | 19,30.02,10.41353940101522,0,0,0,0,0,0,1,1,0,0 1199 | 41,33.55,8.648192944644329,1,0,0,0,0,0,0,0,1,0 1200 | 40,29.355,8.763053308616136,1,1,0,0,0,0,0,1,0,0 1201 | 31,25.8,8.50404817297853,0,0,1,0,0,0,0,0,0,1 1202 | 37,24.32,8.732103228184426,1,0,1,0,0,0,0,1,0,0 1203 | 46,40.375,9.074890483071128,1,0,1,0,0,0,0,1,0,0 1204 | 22,32.11,7.628189216623282,1,0,0,0,0,0,0,1,0,0 1205 | 51,32.3,9.206739898041981,1,1,0,0,0,0,0,0,0,0 1206 | 18,27.28,9.810464571098317,0,0,0,1,0,0,1,0,1,0 1207 | 35,17.86,8.540225968705249,1,1,0,0,0,0,0,1,0,0 1208 | 59,34.8,10.516254269201825,0,0,1,0,0,0,0,0,0,1 1209 | 36,33.4,10.556215626155717,1,0,1,0,0,0,1,0,0,1 1210 | 37,25.555,9.918221643239786,0,1,0,0,0,0,1,0,0,0 1211 | 59,37.1,9.42118232798015,1,1,0,0,0,0,0,0,0,1 1212 | 36,30.875,8.589209481098042,1,1,0,0,0,0,0,1,0,0 1213 | 39,34.1,10.067433650793916,1,0,1,0,0,0,0,0,1,0 1214 | 18,21.47,7.439826782172378,1,0,0,0,0,0,0,0,0,0 1215 | 52,33.3,9.287934453440736,0,0,1,0,0,0,0,0,0,1 1216 | 27,31.255,8.283006753752403,0,1,0,0,0,0,0,1,0,0 1217 | 18,39.14,9.464211568382503,1,0,0,0,0,0,0,0,0,0 1218 | 40,25.08,8.597050257244009,1,0,0,0,0,0,0,0,1,0 1219 | 29,37.29,8.308474130129282,1,0,1,0,0,0,0,0,1,0 1220 | 46,34.6,10.637335168228285,0,1,0,0,0,0,1,0,0,1 1221 | 38,30.21,8.927601249659833,0,0,0,1,0,0,0,1,0,0 1222 | 30,21.945,8.459183402318027,0,1,0,0,0,0,0,0,0,0 1223 | 40,24.97,8.793840853062461,1,0,1,0,0,0,0,0,1,0 1224 | 50,25.3,9.04105353293468,1,0,0,0,0,0,0,0,1,0 1225 | 20,24.42,10.170673817450307,0,0,0,0,0,0,1,0,1,0 1226 | 41,23.94,8.833241063502724,1,1,0,0,0,0,0,0,0,0 1227 | 33,39.82,8.475465953953865,0,1,0,0,0,0,0,0,1,0 1228 | 38,16.815,8.800949294826985,1,0,1,0,0,0,0,0,0,0 1229 | 42,37.18,8.876546253991721,1,0,1,0,0,0,0,0,1,0 1230 | 56,34.43,9.268064386389522,1,0,0,0,0,0,0,0,1,0 1231 | 58,30.305,9.387503308438452,1,0,0,0,0,0,0,0,0,0 1232 | 52,34.485,11.002456427119922,1,0,0,1,0,0,1,1,0,0 1233 | 20,21.8,9.911819546370243,0,0,0,0,0,0,1,0,0,1 1234 | 54,24.605,9.43185932033737,0,0,0,1,0,0,0,1,0,0 1235 | 58,23.3,9.3365781431927,1,0,0,0,0,0,0,0,0,1 1236 | 45,27.83,9.049673690712916,0,0,1,0,0,0,0,0,1,0 1237 | 26,31.065,7.900847168841421,1,0,0,0,0,0,0,1,0,0 1238 | 63,21.66,9.578439617365246,0,0,0,0,0,0,0,0,0,0 1239 | 58,28.215,9.411185212728707,0,0,0,0,0,0,0,1,0,0 1240 | 37,22.705,8.85159284600809,1,0,0,1,0,0,0,0,0,0 1241 | 25,42.13,8.08284568355478,0,1,0,0,0,0,0,0,1,0 1242 | 52,41.8,10.763628035142784,1,0,1,0,0,0,1,0,1,0 1243 | 64,36.96,10.811295656434112,1,0,1,0,0,0,1,0,1,0 1244 | 22,21.28,8.365502762687802,0,0,0,1,0,0,0,1,0,0 1245 | 28,33.11,8.061996169331463,0,0,0,0,0,0,0,0,1,0 1246 | 18,33.33,7.035216397214367,1,0,0,0,0,0,0,0,1,0 1247 | 28,24.3,8.633262581843207,1,0,0,0,0,1,0,0,0,1 1248 | 45,25.7,9.116227255405688,0,0,0,1,0,0,0,0,0,1 1249 | 33,29.4,8.709328601103802,1,0,0,0,1,0,0,0,0,1 1250 | 18,39.82,7.398762896933699,0,0,0,0,0,0,0,0,1,0 1251 | 32,33.63,10.534959514126916,1,1,0,0,0,0,1,0,0,0 1252 | 24,29.83,9.833516794145021,1,0,0,0,0,0,1,0,0,0 1253 | 19,19.8,7.124127959598635,1,0,0,0,0,0,0,0,0,1 1254 | 20,27.3,9.694792061021555,1,0,0,0,0,0,1,0,0,1 1255 | 40,29.3,9.669587717382127,0,0,0,0,1,0,0,0,0,1 1256 | 34,27.72,8.392799080681138,0,0,0,0,0,0,0,0,1,0 1257 | 42,37.9,8.775551442516303,0,0,0,0,0,0,0,0,0,1 1258 | 51,36.385,9.344586097529177,0,0,0,1,0,0,0,1,0,0 1259 | 54,27.645,9.333083048256867,0,1,0,0,0,0,0,1,0,0 1260 | 55,37.715,10.31106976965331,1,0,0,1,0,0,0,1,0,0 1261 | 52,23.18,9.229924563652334,0,0,0,0,0,0,0,0,0,0 1262 | 32,20.52,8.42161463160122,0,0,0,0,0,0,0,0,0,0 1263 | 28,37.1,8.094732777794066,1,1,0,0,0,0,0,0,0,1 1264 | 41,28.05,8.820284799770908,0,1,0,0,0,0,0,0,1,0 1265 | 43,29.9,8.900787262543032,0,1,0,0,0,0,0,0,0,1 1266 | 49,33.345,9.246760296387565,0,0,1,0,0,0,0,0,0,0 1267 | 64,23.76,10.20086674556824,1,0,0,0,0,0,1,0,1,0 1268 | 55,30.5,9.278416690223178,0,0,0,0,0,0,0,0,0,1 1269 | 24,31.065,10.44156018267344,1,0,0,0,0,0,1,0,0,0 1270 | 20,33.3,7.539286064831457,0,0,0,0,0,0,0,0,0,1 1271 | 45,27.5,9.061294971338892,1,0,0,1,0,0,0,0,0,1 1272 | 26,33.915,8.099411499635565,1,1,0,0,0,0,0,1,0,0 1273 | 25,34.485,8.013610987297714,0,0,0,0,0,0,0,1,0,0 1274 | 43,25.52,9.580408338157117,1,0,0,0,0,1,0,0,1,0 1275 | 35,27.61,8.46527926236957,1,1,0,0,0,0,0,0,1,0 1276 | 26,27.06,9.743514872709168,1,0,0,0,0,0,1,0,1,0 1277 | 57,23.7,9.301946427246547,1,0,0,0,0,0,0,0,0,1 1278 | 22,30.4,7.9164238956827715,0,0,0,0,0,0,0,0,0,0 1279 | 32,29.735,8.379549044428517,0,0,0,0,0,0,0,1,0,0 1280 | 39,29.925,10.019582219255035,1,1,0,0,0,0,1,0,0,0 1281 | 25,26.79,8.340244319866398,0,0,1,0,0,0,0,1,0,0 1282 | 48,33.33,9.022042677591074,0,0,0,0,0,0,0,0,1,0 1283 | 47,27.645,10.10788441968992,0,0,1,0,0,0,1,1,0,0 1284 | 18,21.66,9.566857461456555,0,0,0,0,0,0,1,0,0,0 1285 | 18,30.03,7.450285188201471,1,1,0,0,0,0,0,0,1,0 1286 | 61,36.3,10.766459360873188,1,1,0,0,0,0,1,0,0,1 1287 | 47,24.32,9.051892181062124,0,0,0,0,0,0,0,0,0,0 1288 | 28,17.29,8.224867045261597,0,0,0,0,0,0,0,0,0,0 1289 | 36,25.9,8.6074815100297,0,1,0,0,0,0,0,0,0,1 1290 | 20,39.4,10.554368101840476,1,0,1,0,0,0,1,0,0,1 1291 | 44,34.32,8.874514118662818,1,1,0,0,0,0,0,0,1,0 1292 | 38,19.95,8.872613698878428,0,0,1,0,0,0,0,0,0,0 1293 | 19,34.9,10.45819571776692,1,0,0,0,0,0,1,0,0,1 1294 | 21,23.21,7.323398348799277,1,0,0,0,0,0,0,0,1,0 1295 | 46,25.745,9.13797326594303,1,0,0,1,0,0,0,1,0,0 1296 | 58,25.175,9.386905831683409,1,0,0,0,0,0,0,0,0,0 1297 | 20,22.0,7.583135558747921,1,1,0,0,0,0,0,0,0,1 1298 | 18,26.125,7.443620235711848,1,0,0,0,0,0,0,0,0,0 1299 | 28,26.51,8.375731211796301,0,0,1,0,0,0,0,0,1,0 1300 | 33,27.455,8.568165629835017,1,0,1,0,0,0,0,1,0,0 1301 | 19,25.745,7.905009605152786,0,1,0,0,0,0,0,1,0,0 1302 | 45,30.36,11.044406702204412,1,0,0,0,0,0,1,0,1,0 1303 | 62,30.875,10.751888302731006,1,0,0,1,0,0,1,1,0,0 1304 | 25,20.8,8.073648263088874,0,1,0,0,0,0,0,0,0,1 1305 | 43,27.8,10.540850427090321,1,0,0,0,0,0,1,0,0,1 1306 | 42,24.605,9.964553392295727,1,0,1,0,0,0,1,0,0,0 1307 | 24,27.72,7.809792429487589,0,0,0,0,0,0,0,0,1,0 1308 | 29,21.85,9.687524689510054,0,0,0,0,0,0,1,0,0,0 1309 | 32,28.12,9.974527338330544,1,0,0,0,1,0,1,1,0,0 1310 | 25,30.2,10.431189555719895,0,0,0,0,0,0,1,0,0,1 1311 | 41,32.2,8.835786694584385,1,0,1,0,0,0,0,0,0,1 1312 | 42,26.315,8.84518814721317,1,1,0,0,0,0,0,1,0,0 1313 | 33,26.695,8.427577637408286,0,0,0,0,0,0,0,1,0,0 1314 | 34,42.9,8.419857942542947,1,1,0,0,0,0,0,0,0,1 1315 | 19,34.7,10.5022574580008,0,0,1,0,0,0,1,0,0,1 1316 | 30,23.655,9.83979536382488,0,0,0,1,0,0,1,1,0,0 1317 | 18,28.31,9.330106452543097,1,1,0,0,0,0,0,0,0,0 1318 | 19,20.6,7.456845582123641,0,0,0,0,0,0,0,0,0,1 1319 | 18,53.13,7.059155923784115,1,0,0,0,0,0,0,0,1,0 1320 | 35,39.71,9.878001482704299,1,0,0,0,1,0,0,0,0,0 1321 | 39,26.315,8.882072506273097,0,0,1,0,0,0,0,1,0,0 1322 | 31,31.065,8.598777482546863,1,0,0,1,0,0,0,1,0,0 1323 | 62,26.695,10.2435722936984,1,0,0,0,0,0,1,0,0,0 1324 | 62,38.83,9.471268659768649,1,0,0,0,0,0,0,0,1,0 1325 | 42,40.37,10.689587051237151,0,0,1,0,0,0,1,0,1,0 1326 | 31,25.935,8.352293229509261,1,1,0,0,0,0,0,1,0,0 1327 | 61,33.535,9.48367019054946,1,0,0,0,0,0,0,0,0,0 1328 | 42,32.87,8.860785917078346,0,0,0,0,0,0,0,0,0,0 1329 | 51,30.03,9.14611163751643,1,1,0,0,0,0,0,0,1,0 1330 | 23,24.225,10.016626230507166,0,0,1,0,0,0,0,0,0,0 1331 | 52,38.6,9.242343369204054,1,0,1,0,0,0,0,0,0,1 1332 | 57,25.74,9.44376414823737,0,0,1,0,0,0,0,0,1,0 1333 | 23,33.4,9.286925169193296,0,0,0,0,0,0,0,0,0,1 1334 | 52,44.7,9.342393109428775,0,0,0,1,0,0,0,0,0,1 1335 | 50,30.97,9.268661005177488,1,0,0,1,0,0,0,1,0,0 1336 | 18,31.92,7.698927496239761,0,0,0,0,0,0,0,0,0,0 1337 | 18,36.85,7.39623314134416,0,0,0,0,0,0,0,0,1,0 1338 | 21,25.8,7.604867089998248,0,0,0,0,0,0,0,0,0,1 1339 | 61,29.07,10.279913760197052,0,0,0,0,0,0,1,1,0,0 1340 | -------------------------------------------------------------------------------- /Need for Blockchain/model_logs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repeatedd/federated-learning-blockchain/57fc408ebb990130d128e05df63538669e1f8b0f/Need for Blockchain/model_logs -------------------------------------------------------------------------------- /Need for Blockchain/server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import pickle 3 | import threading 4 | import time 5 | 6 | import pygad 7 | import pygad.nn 8 | import pygad.gann 9 | import numpy 10 | import pandas 11 | import backprop as bp 12 | 13 | model = None 14 | counter = 0 15 | 16 | df = pandas.read_csv('data.csv') 17 | 18 | X = df.drop('charges', axis=1) 19 | y = df['charges'] 20 | 21 | y = numpy.array(y) 22 | y = y.reshape((len(y), 1)) 23 | 24 | 25 | # Preparing the NumPy array of the inputs. 26 | data_inputs = numpy.array(X) 27 | # Preparing the NumPy array of the outputs. 28 | data_outputs = y 29 | 30 | data_inputs = data_inputs.T 31 | data_outputs = data_outputs.T 32 | 33 | mean = numpy.mean(data_inputs, axis = 1, keepdims=True) 34 | std_dev = numpy.std(data_inputs, axis = 1, keepdims=True) 35 | data_inputs = (data_inputs - mean)/std_dev 36 | 37 | 38 | num_classes = 1 39 | num_inputs = 12 40 | sema = threading.Semaphore() 41 | 42 | # num_solutions = 6 43 | # GANN_instance = pygad.gann.GANN(num_solutions=num_solutions, 44 | # num_neurons_input=num_inputs, 45 | # num_neurons_hidden_layers=[12], 46 | # num_neurons_output=num_classes, 47 | # hidden_activations=["relu"], 48 | # output_activation="relu") 49 | 50 | description = [{"num_nodes" : 12, "activation" : "relu"}, 51 | {"num_nodes" : 1, "activation" : "relu"}] 52 | 53 | NN_model = bp.NeuralNetwork(description,num_inputs,"mean_squared", data_inputs, data_outputs, learning_rate=0.001) 54 | 55 | class SocketThread(threading.Thread): 56 | 57 | def __init__(self, connection, client_info, buffer_size=1024, recv_timeout=5): 58 | threading.Thread.__init__(self) 59 | self.connection = connection 60 | self.client_info = client_info 61 | self.buffer_size = buffer_size 62 | self.recv_timeout = recv_timeout 63 | # self.lock = threading.Lock() 64 | 65 | def recv(self): 66 | received_data = b"" 67 | while True: 68 | try: 69 | 70 | data = self.connection.recv(self.buffer_size) 71 | received_data += data 72 | 73 | if data == b'': # Nothing received from the client. 74 | received_data = b"" 75 | # If still nothing received for a number of seconds specified by the recv_timeout attribute, return with status 0 to close the connection. 76 | if (time.time() - self.recv_start_time) > self.recv_timeout: 77 | return None, 0 # 0 means the connection is no longer active and it should be closed. 78 | 79 | elif str(received_data)[-18:-7] == '-----------': 80 | # print(str(received_data)[-19:-8]) 81 | # print("All data ({data_len} bytes) Received from {client_info}.".format(client_info=self.client_info, data_len=len(received_data))) 82 | 83 | if len(received_data) > 0: 84 | try: 85 | # Decoding the data (bytes). 86 | received_data = pickle.loads(received_data) 87 | # Returning the decoded data. 88 | return received_data, 1 89 | 90 | except BaseException as e: 91 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 92 | return None, 0 93 | 94 | else: 95 | # In case data are received from the client, update the recv_start_time to the current time to reset the timeout counter. 96 | self.recv_start_time = time.time() 97 | 98 | except BaseException as e: 99 | print("Error Receiving Data from the Client: {msg}.\n".format(msg=e)) 100 | return None, 0 101 | 102 | def model_averaging(self, model, other_model): 103 | # print("Model ", model.layers) 104 | # print("Other_Model ",other_model.layers) 105 | for i in range(len(model.layers)): 106 | W_a = model.layers[i].W 107 | W_b = other_model.layers[i].W 108 | b_a = model.layers[i].b 109 | b_b = other_model.layers[i].b 110 | model.layers[i].W = (W_a + W_b)/2 111 | model.layers[i].b = (b_a + b_b)/2 112 | 113 | # print("Updated model", model.layers) 114 | 115 | return model 116 | 117 | 118 | # model_weights = numpy.array(model_weights) 119 | # other_model_weights = numpy.array(other_model_weights) 120 | # print("Shape of model",model_weights.shape) 121 | # new_weights = numpy.mean([model_weights, other_model_weights], axis=0) 122 | 123 | # pygad.nn.update_layers_trained_weights(last_layer=model, final_weights=new_weights) 124 | 125 | def reply(self, received_data): 126 | # self.lock.acquire() 127 | global NN_model, data_inputs, data_outputs, model, counter 128 | if (type(received_data) is dict): 129 | if (("data" in received_data.keys()) and ("subject" in received_data.keys())): 130 | subject = received_data["subject"] 131 | # print("Client's Message Subject is {subject}.".format(subject=subject)) 132 | 133 | # print("Replying from Client.", received_data) 134 | if subject == "echo": 135 | if model is None: 136 | data = {"subject": "model", "data": NN_model, "mark": "-----------"} 137 | # f = open("logs_ser","a") 138 | # f.write(str(NN_model.tolist())) 139 | # f.write("---------------------------\n") 140 | # f.close() 141 | else: 142 | model.data = data_inputs 143 | model.labels = data_outputs 144 | model.forward_pass() 145 | 146 | predictions = model.layers[-1].a 147 | error = model.calc_accuracy(data_inputs, data_outputs, "RMSE") 148 | model = bp.NeuralNetwork(description,num_inputs,"mean_squared", data_inputs, data_outputs, learning_rate=0.001) 149 | 150 | # error = numpy.sum(numpy.abs(predictions - data_outputs))/data_outputs.shape[0] 151 | # In case a client sent a model to the server despite that the model error is 0.0. In this case, no need to make changes in the model. 152 | if error == 0: 153 | data = {"subject": "done", "data": model, "mark": "-----------"} 154 | else: 155 | data = {"subject": "model", "data": model, "mark": "-----------"} 156 | 157 | try: 158 | response = pickle.dumps(data) 159 | except BaseException as e: 160 | print("Error Encoding the Message: {msg}.\n".format(msg=e)) 161 | elif subject == "model": 162 | try: 163 | best_model = received_data["data"] 164 | # best_model_idx = received_data["best_solution_idx"] 165 | # print(GANN_instance, best_model_idx) 166 | # best_model = GANN_instance.population_networks[best_model_idx] 167 | if model is None: 168 | model = best_model 169 | print(model) 170 | else: 171 | # print("shape of data {input}".format(input=data_inputs.shape)) 172 | model.data = data_inputs 173 | model.labels = data_outputs 174 | model.forward_pass() 175 | 176 | predictions = model.layers[-1].a 177 | 178 | # predictions = numpy.array(predictions) 179 | 180 | # predictions = predictions.reshape((-1,)) 181 | # print("predictions shape", predictions.shape) 182 | # print("data shape", data_outputs.shape) 183 | 184 | error = model.calc_accuracy(data_inputs, data_outputs, "RMSE") 185 | # In case a client sent a model to the server despite that the model error is 0.0. In this case, no need to make changes in the model. 186 | if error <= 0.15: 187 | data = {"subject": "done", "data": None, "mark": "-----------"} 188 | response = pickle.dumps(data) 189 | # print("Error in total {}".format(error)) 190 | # return 191 | else: 192 | model = self.model_averaging(model, best_model) 193 | 194 | # print(best_model.trained_weights) 195 | # print(model.trained_weights) 196 | # print(model, best_model) 197 | # self.model_averaging(model, best_model) 198 | 199 | 200 | 201 | model.data = data_inputs 202 | model.labels = data_outputs 203 | model.forward_pass() 204 | 205 | predictions = model.layers[-1].a 206 | 207 | # predictions = numpy.array(predictions) 208 | # predictions = predictions.reshape((-1,)) 209 | # print("Model Predictions: {predictions}".format(predictions=predictions)) 210 | 211 | error = model.calc_accuracy(data_inputs, data_outputs, "MAE") 212 | print("Error(RMSE) from {info} = {error}".format(error=error, info=self.client_info)) 213 | counter+=1 214 | print("counter ",counter) 215 | # f = open("logs_ser","a") 216 | # f.write(str(model.tolist())) 217 | # f.write("---------------------------\n") 218 | # f.close() 219 | 220 | model = bp.NeuralNetwork(description,num_inputs,"mean_squared", data_inputs, data_outputs, learning_rate=0.001) 221 | 222 | if error >= 0.15: 223 | data = {"subject": "model", "data": model, "mark": "-----------"} 224 | print("sent", data) 225 | response = pickle.dumps(data) 226 | print("data_sent", len(response)) 227 | 228 | else: 229 | data = {"subject": "done", "data": None, "mark": "-----------"} 230 | response = pickle.dumps(data) 231 | 232 | except BaseException as e: 233 | print("Error Decoding the Client's Data: {msg}.\n".format(msg=e)) 234 | else: 235 | response = pickle.dumps("Response from the Server") 236 | 237 | try: 238 | # print("Len of data sent {}".format(len(response))) 239 | self.connection.sendall(response) 240 | except BaseException as e: 241 | print("Error Sending Data to the Client: {msg}.\n".format(msg=e)) 242 | 243 | else: 244 | print("The received dictionary from the client must have the 'subject' and 'data' keys available. The existing keys are {d_keys}.".format(d_keys=received_data.keys())) 245 | else: 246 | print("A dictionary is expected to be received from the client but {d_type} received.".format(d_type=type(received_data))) 247 | # self.lock.release() 248 | 249 | def run(self): 250 | # print("Running a Thread for the Connection with {client_info}.".format(client_info=self.client_info)) 251 | 252 | # This while loop allows the server to wait for the client to send data more than once within the same connection. 253 | while True: 254 | self.recv_start_time = time.time() 255 | time_struct = time.gmtime() 256 | date_time = "Waiting to Receive Data Starting from {day}/{month}/{year} {hour}:{minute}:{second} GMT".format(year=time_struct.tm_year, month=time_struct.tm_mon, day=time_struct.tm_mday, hour=time_struct.tm_hour, minute=time_struct.tm_min, second=time_struct.tm_sec) 257 | print(date_time) 258 | received_data, status = self.recv() 259 | if status == 0: 260 | self.connection.close() 261 | print("Connection Closed with {client_info} either due to inactivity for {recv_timeout} seconds or due to an error.".format(client_info=self.client_info, recv_timeout=self.recv_timeout), end="\n\n") 262 | break 263 | 264 | # print(received_data) 265 | sema.acquire() 266 | self.reply(received_data) 267 | sema.release() 268 | 269 | soc = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) 270 | print("Socket Created.\n") 271 | 272 | # Timeout after which the socket will be closed. 273 | # soc.settimeout(5) 274 | 275 | soc.bind(("localhost", 10000)) 276 | print("Socket Bound to IPv4 Address & Port Number.\n") 277 | 278 | soc.listen(1) 279 | print("Socket is Listening for Connections ....\n") 280 | 281 | all_data = b"" 282 | while True: 283 | try: 284 | connection, client_info = soc.accept() 285 | # print("New Connection from {client_info}.".format(client_info=client_info)) 286 | socket_thread = SocketThread(connection=connection, 287 | client_info=client_info, 288 | buffer_size=1024, 289 | recv_timeout=10) 290 | socket_thread.start() 291 | except: 292 | soc.close() 293 | print("(Timeout) Socket Closed Because no Connections Received.\n") 294 | break 295 | -------------------------------------------------------------------------------- /Need for Blockchain/stats.txt: -------------------------------------------------------------------------------- 1 | 2 | Model: "Linear Regression Model" 3 | Error with 1 agent 4 | client1 error(RMSE): 0.52 (half data) 5 | server error (RMSE): 0.6181 (full data) 6 | 7 | Error with 2 agents 8 | client1 error(RMSE): 0.52 (half data) 9 | client2 error(RMSE): 0.53 (other half) 10 | server error(RMSE): 0.6151 (full data) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Federated Learning with Blockchain 2 | A simple application that uses Blockchain to demonstrate federated learning. 3 | 4 | ## What is Federated Learning? 5 | 6 | 7 | Machine learning models trained on sensitive real-world data promise improvements to everything 8 | from medical screening to disease outbreak discovery. And the widespread use of mobile devices 9 | means even richer and more sensitive data is becoming available. However, traditional machine 10 | learning involves a data pipeline that uses a central server(on-premise or cloud) that hosts the trained 11 | model to make predictions. Distributed Machine Learning (FL) in contrast, is an approach that 12 | downloads the current model and computes an updated model at the device itself (also known as edge 13 | computing) using local data. Federated learning (FL) is a machine learning setting where many clients 14 | (e.g. mobile devices or whole organizations) collaboratively train a model under the orchestration of a 15 | central server (e.g. service provider) while keeping the training data decentralized. 16 | Most of the previous research-work in federated learning focuses on the transfer and aggregation of the 17 | gradients for learning on linear models and very less work is available on non-linear models. In this 18 | project, we explore a secure decentralized learning model using neural networks. The motivation for 19 | the same came from blockchain, preserving the user identities without a trusted central server and the 20 | hidden layers in a neural network, able to add non-linearity to the model. Analogous to the transfer of 21 | gradients in the federated learning system which requires a lot of network communication, we explore 22 | the possibility of broadcasting weights to the blockchain system. 23 | The goals of this work are to highlight research problems that are of significant theoretical and practical 24 | interest and to encourage research on problems that could have significant real-world impact. 25 | 26 | [blog](https://ai.googleblog.com/2017/04/federated-learning-collaborative.html) 27 | 28 | ## Setup 29 | Make sure you have python3, pip setup on your machine. 30 | 31 | ## Distributed Linear Regression Model 32 | 33 | > ***Working Code Dir:*** Federated(linear Regression) 34 | > 35 | > ***Install librabries*** 36 | > > - pygad 37 | > > - numpy 38 | > > - pandas 39 | > > - pickle 40 | > 41 | > ***Running of the Code*** 42 | > > - Open 3 terminals 43 | > > - In first terminal, run ***python server.py*** 44 | > > - In second terminal, run ***python client1.py*** 45 | > > - In third terminal, run ***python client2.py*** 46 | 47 | ## Distributed Blockchain Model 48 | 49 | > ***Working Code Dir:*** Federated(linear regression + blockchain) 50 | > 51 | > ***Structure of the block*** 52 | >> Block - 53 | >> - index 54 | >> - client_model 55 | >> - server_model 56 | >> - cli - [“cli1”, “cli2”] 57 | >> - timestamp 58 | >> - previous_hash 59 | >> - nonce 60 | > 61 | > ***Hashing of the Block*** 62 | >> Hash - 63 | >> - index 64 | >> - client_weights 65 | >> - client_biases 66 | >> - cli 67 | >> - timestamp 68 | >> - previous_hash 69 | >> - nonce 70 | > 71 | > ***Running of the Code*** 72 | > > - Open 3 terminals 73 | > > - In first terminal, run ***python server.py*** 74 | > > - In second terminal, run ***python client1.py*** 75 | > > - In third terminal, run ***python client2.py*** 76 | --------------------------------------------------------------------------------