diff --git a/eval/.ipynb_checkpoints/ip_addr_7Machines-checkpoint.json b/eval/.ipynb_checkpoints/ip_addr_7Machines-checkpoint.json new file mode 100644 index 0000000000000000000000000000000000000000..889afa03d3f0173318e51c13c3f3f2a17cc7c88e --- /dev/null +++ b/eval/.ipynb_checkpoints/ip_addr_7Machines-checkpoint.json @@ -0,0 +1,9 @@ +{ + "0": "10.90.41.127", + "1": "10.90.41.128", + "2": "10.90.41.129", + "3": "10.90.41.130", + "4": "10.90.41.131", + "5": "10.90.41.132", + "6": "10.90.41.133" +} \ No newline at end of file diff --git a/eval/16_regular.edges b/eval/16_regular.edges new file mode 100644 index 0000000000000000000000000000000000000000..4e847b9534add5352272851013ac3c1994f09b43 --- /dev/null +++ b/eval/16_regular.edges @@ -0,0 +1,49 @@ +16 +0 1 +0 3 +0 15 +1 0 +1 10 +1 2 +2 1 +2 3 +2 15 +3 0 +3 2 +3 4 +4 9 +4 3 +4 5 +5 4 +5 13 +5 6 +6 11 +6 5 +6 7 +7 8 +7 14 +7 6 +8 9 +8 12 +8 7 +9 8 +9 10 +9 4 +10 1 +10 11 +10 9 +11 10 +11 12 +11 6 +12 8 +12 11 +12 13 +13 12 +13 5 +13 14 +14 15 +14 13 +14 7 +15 0 +15 2 +15 14 diff --git a/eval/ip_addr_1Machines.json b/eval/ip_addr_1Machines.json new file mode 100644 index 0000000000000000000000000000000000000000..15d6591df53574707ac03627fa19c9ecd749b1e3 --- /dev/null +++ b/eval/ip_addr_1Machines.json @@ -0,0 +1,3 @@ +{ + "0": "127.0.0.1" +} \ No newline at end of file diff --git a/eval/run_grid1.sh b/eval/run_grid1.sh new file mode 100755 index 0000000000000000000000000000000000000000..e8e6659b39927f75896a98347d8a2d0fea8f69a0 --- /dev/null +++ b/eval/run_grid1.sh @@ -0,0 +1,107 @@ +#!/bin/bash +# Documentation +# This bash file takes three inputs. The first argument (nfs_home) is the path to the nfs home directory. +# The second one (python_bin) is the path to the python bin folder. +# The last argument (logs_subfolder) is the path to the logs folder with respect to the nfs home directory. +# +# The nfs home directory should contain the code of this framework stored in $nfs_home/decentralizepy and a folder +# called configs which contains the file 'ip_addr_6Machines.json' +# The python bin folder needs to include all the dependencies of this project including crudini. +# The results will be stored in $nfs_home/$logs_subfolder +# Each of the experiments will be stored in its own folder inside the logs_subfolder. The folder of the experiment +# starts with the last part of the config name, i.e., for 'config_celeba_topkacc.ini' it will start with topkacc. +# The name further includes the learning rate, rounds and batchsize as well as the exact date at which the experiment +# was run. +# Example: ./run_grid.sh /mnt/nfs/wigger /mnt/nfs/wigger/anaconda3/envs/sacs39/bin /logs/celaba +# +# Additional requirements: +# Each node needs a folder called 'tmp' in the user's home directory +# +# Note: +# - The script does not change the optimizer. All configs are writen to use Adam. +# For SGD these need to be changed manually +# - The script will set '--test_after' and '--train_evaluate_after' to comm_rounds_per_global_epoch, i.e., the eavaluation +# on the train set and on the test set is carried out every global epoch. +# - The '--reset_optimizer' option is set to 0, i.e., the optimizer is not reset after a communication round (only +# relevant for Adams and other optimizers with internal state) +# +# Addapting the script to other datasets: +# Change the variable 'dataset_size' to reflect the data sets size. +# +# Known issues: +# - If the script is started at the very end of a minute then there is a change that two folders are created as not all +# machines may start running the script at the exact same moment. + +nfs_home=$1 +python_bin=$2 +logs_subfolder=$3 +decpy_path=$nfs_home/decentralizepy/eval +cd $decpy_path + +env_python=$python_bin/python3 +graph=192_regular.edges +config_file=~/tmp/config.ini +procs_per_machine=32 +machines=6 +global_epochs=25 +eval_file=testing.py +log_level=INFO + +ip_machines=$nfs_home/configs/ip_addr_6Machines.json + +m=`cat $ip_machines | grep $(/sbin/ifconfig ens785 | grep 'inet ' | awk '{print $2}') | cut -d'"' -f2` +export PYTHONFAULTHANDLER=1 + +# Base configs for which the gird search is done +tests=("step_configs/config_celeba_sharing.ini") +# Learning rates to test +lrs=( "0.1" "0.01" "0.001") + +batchsize=("8" "16") +comm_rounds_per_global_epoch=("1" "10" "100") +# Celeba has 63741 samples +procs=`expr $procs_per_machine \* $machines` +echo procs: $procs +dataset_size=63741 +samples_per_user=`expr $dataset_size / $procs` +echo samples per user: $samples_per_user + +for b in "${batchsize[@]}" +do + echo batchsize: $b + for r in "${comm_rounds_per_global_epoch[@]}" + do + echo communication rounds per global epoch: $r + batches_per_epoch=$(($samples_per_user / $b)) + echo batches per global epoch: $batches_per_epoch + iterations=$(($global_epochs * $r)) + echo iterations: $iterations + batches_per_comm_round=$($env_python -c "from math import floor; x = floor($batches_per_epoch / $r); print(1 if x==0 else x)") + new_iterations=$($env_python -c "from math import floor; x = floor($batches_per_epoch / $r); y = floor((($batches_per_epoch / $r) -x +1)*$iterations); print($iterations if x==0 else y)") + echo batches per communication round: $batches_per_comm_round + echo corrected iterations: $new_iterations + for lr in "${lrs[@]}" + do + for i in "${tests[@]}" + do + echo $i + IFS='_' read -ra NAMES <<< $i + IFS='.' read -ra NAME <<< ${NAMES[-1]} + log_dir=$nfs_home$logs_subfolder/${NAME[0]}:lr=$lr:r=$r:b=$b:$(date '+%Y-%m-%dT%H:%M')/machine$m + echo results are stored in: $log_dir + mkdir -p $log_dir + cp $i $config_file + $python_bin/crudini --set $config_file COMMUNICATION addresses_filepath $ip_machines + $python_bin/crudini --set $config_file OPTIMIZER_PARAMS lr $lr + $python_bin/crudini --set $config_file TRAIN_PARAMS rounds $batches_per_comm_round + $python_bin/crudini --set $config_file TRAIN_PARAMS batch_size $b + $env_python $eval_file -ro 0 -tea $r -ld $log_dir -mid $m -ps $procs_per_machine -ms $machines -is $new_iterations -gf $graph -ta $r -cf $config_file -ll $log_level + echo $i is done + sleep 1 + echo end of sleep + done + done + done +done +# + diff --git a/eval/run_grid_server.sh b/eval/run_grid_server.sh new file mode 100755 index 0000000000000000000000000000000000000000..b5b9982e15509446fc65c04f5fc7bb9f7b45e8b0 --- /dev/null +++ b/eval/run_grid_server.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# Documentation +# This bash file takes three inputs. The first argument (nfs_home) is the path to the nfs home directory. +# The second one (python_bin) is the path to the python bin folder. +# The last argument (logs_subfolder) is the path to the logs folder with respect to the nfs home directory. +# +# The nfs home directory should contain the code of this framework stored in $nfs_home/decentralizepy and a folder +# called configs which contains the file 'ip_addr_6Machines.json' +# The python bin folder needs to include all the dependencies of this project including crudini. +# The results will be stored in $nfs_home/$logs_subfolder +# Each of the experiments will be stored in its own folder inside the logs_subfolder. The folder of the experiment +# starts with the last part of the config name, i.e., for 'config_celeba_topkacc.ini' it will start with topkacc. +# The name further includes the learning rate, rounds and batchsize as well as the exact date at which the experiment +# was run. +# Example: +# +# Note: +# - The script does not change the optimizer. All configs are writen to use Adam. +# For SGD these need to be changed manually +# - The script will set '--test_after' and '--train_evaluate_after' to comm_rounds_per_global_epoch, i.e., the eavaluation +# on the train set and on the test set is carried out every global epoch. +# - The '--reset_optimizer' option is set to 0, i.e., the optimizer is not reset after a communication round (only +# relevant for Adams and other optimizers with internal state) +# +# +# Known issues: +# - If the script is started at the very end of a minute then there is a change that two folders are created as not all +# machines may start running the script at the exact same moment. + +nfs_home=$1 +python_bin=$2 +logs_subfolder=$3 +decpy_path=$nfs_home/decentralizepy/eval +cd $decpy_path + +env_python=$python_bin/python3 +graph=192_regular.edges #4_node_fullyConnected.edges +config_file=~/tmp/config.ini +procs_per_machine=32 +machines=6 +global_epochs=1 +eval_file=testing.py +log_level=INFO + +ip_machines=$nfs_home/configs/ip_addr_6Machines.json + +m=`cat $ip_machines | grep $(/sbin/ifconfig ens785 | grep 'inet ' | awk '{print $2}') | cut -d'"' -f2` +export PYTHONFAULTHANDLER=1 + +# Base configs for which the gird search is done +tests=("step_configs/config_celeba_sharing.ini") +# Learning rates to test +lrs=( "0.1" "0.01") + +batchsize=("8" "16") +comm_rounds_per_global_epoch=("1" "10") +# Celeba has 63741 samples +procs=`expr $procs_per_machine \* $machines` +echo procs: $procs +dataset_size=63741 +samples_per_user=`expr $dataset_size / $procs` +echo samples per user: $samples_per_user + +for b in "${batchsize[@]}" +do + echo batchsize: $b + for r in "${comm_rounds_per_global_epoch[@]}" + do + echo communication rounds per global epoch: $r + batches_per_epoch=$(($samples_per_user / $b)) + echo batches per global epoch: $batches_per_epoch + iterations=$(($global_epochs * $r)) + echo iterations: $iterations + batches_per_comm_round=$($env_python -c "from math import floor; x = floor($batches_per_epoch / $r); print(1 if x==0 else x)") + new_iterations=$($env_python -c "from math import floor; x = floor($batches_per_epoch / $r); y = floor((($batches_per_epoch / $r) -x +1)*$iterations); print($iterations if x==0 else y)") + echo batches per communication round: $batches_per_comm_round + echo corrected iterations: $new_iterations + for lr in "${lrs[@]}" + do + for i in "${tests[@]}" + do + echo $i + IFS='_' read -ra NAMES <<< $i + IFS='.' read -ra NAME <<< ${NAMES[-1]} + log_dir=$nfs_home$logs_subfolder/${NAME[0]}:lr=$lr:r=$r:b=$b:$(date '+%Y-%m-%dT%H:%M')/machine$m + echo results are stored in: $log_dir + mkdir -p $log_dir + cp $i $config_file + $python_bin/crudini --set $config_file COMMUNICATION addresses_filepath $ip_machines + $python_bin/crudini --set $config_file OPTIMIZER_PARAMS lr $lr + $python_bin/crudini --set $config_file TRAIN_PARAMS rounds $batches_per_comm_round + $python_bin/crudini --set $config_file TRAIN_PARAMS batch_size $b + $env_python $eval_file -ro 0 -tea $r -ld $log_dir -mid $m -ps $procs_per_machine -ms $machines -is $new_iterations -gf $graph -ta $r -cf $config_file -ll $log_level + echo $i is done + sleep 1 + echo end of sleep + done + done + done +done +# + diff --git a/eval/run_reddit_local2.sh b/eval/run_reddit_local2.sh new file mode 100755 index 0000000000000000000000000000000000000000..5bcebde3c2729c1491f257fcdf03cacf81088abe --- /dev/null +++ b/eval/run_reddit_local2.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# Documentation +# This bash file takes three inputs. The first argument (nfs_home) is the path to the nfs home directory. +# The second one (python_bin) is the path to the python bin folder. +# The last argument (logs_subfolder) is the path to the logs folder with respect to the nfs home directory. +# +# The nfs home directory should contain the code of this framework stored in $nfs_home/decentralizepy and a folder +# called configs which contains the file 'ip_addr_6Machines.json' +# The python bin folder needs to include all the dependencies of this project including crudini. +# The results will be stored in $nfs_home/$logs_subfolder +# Each of the experiments will be stored in its own folder inside the logs_subfolder. The folder of the experiment +# starts with the last part of the config name, i.e., for 'config_celeba_topkacc.ini' it will start with topkacc. +# The name further includes the learning rate, rounds and batchsize as well as the exact date at which the experiment +# was run. +# Example: ./run_grid.sh /mnt/nfs/wigger /mnt/nfs/wigger/anaconda3/envs/sacs39/bin /logs/celeba +# +# Additional requirements: +# Each node needs a folder called 'tmp' in the user's home directory +# +# Note: +# - The script does not change the optimizer. All configs are writen to use SGD. +# - The script will set '--test_after' and '--train_evaluate_after' such that it happens at the end of a global epoch. +# - The '--reset_optimizer' option is set to 0, i.e., the optimizer is not reset after a communication round (only +# relevant for Adams and other optimizers with internal state) +# +# Addapting the script to other datasets: +# Change the variable 'dataset_size' to reflect the data sets size. +# +# Known issues: +# - If the script is started at the very end of a minute then there is a change that two folders are created as not all +# machines may start running the script at the exact same moment. + +nfs_home=/tmp/logs/ +python_bin=/home/jeffrey/anaconda3/envs/sacs39/bin +logs_subfolder=reddit_local + +env_python=$python_bin/python3 +graph=16_regular.edges +config_file=~/tmp/config.ini +procs_per_machine=16 +machines=1 +global_epochs=2 +eval_file=testing.py +log_level=DEBUG + +ip_machines=ip_addr_1Machines.json + +m=`cat $ip_machines | grep $(/sbin/ifconfig ens785 | grep 'inet ' | awk '{print $2}') | cut -d'"' -f2` + +# Base configs for which the gird search is done +tests=("step_configs/config_reddit_jwins+_local.ini") #("step_configs/config_reddit_sharing_local.ini") +# Learning ratesJwinsDynamicGraph.py +lr="1" +# Batch size +batchsize="16" +# The number of communication rounds per global epoch +comm_rounds_per_global_epoch="10" +procs=`expr $procs_per_machine \* $machines` +echo procs: $procs +# Celeba has 63741 samples +# Reddit has 70642 +# Femnist 734463 +# Shakespeares 3678451 +dataset_size=70642 +# Calculating the number of samples that each user/proc will have on average +samples_per_user=`expr $dataset_size / $procs` +echo samples per user: $samples_per_user + +# random_seeds for which to rerun the experiments +random_seeds=("97") +# random_seed = 97 +echo batchsize: $batchsize +echo communication rounds per global epoch: $comm_rounds_per_global_epoch +# calculating how many batches there are in a global epoch for each user/proc +batches_per_epoch=$(($samples_per_user / $batchsize)) +echo batches per global epoch: $batches_per_epoch +# the number of iterations in 25 global epochs +iterations=$($env_python -c "from math import floor; print($batches_per_epoch * $global_epochs) if $comm_rounds_per_global_epoch >= $batches_per_epoch else print($global_epochs * $comm_rounds_per_global_epoch)") +echo iterations: $iterations +# calculating the number of batches each user/proc uses per communication step (The actual number may be a float, which we round down) +batches_per_comm_round=$($env_python -c "from math import floor; x = floor($batches_per_epoch / $comm_rounds_per_global_epoch); print(1 if x==0 else x)") +# since the batches per communication round were rounded down we need to change the number of iterations to reflect that +new_iterations=$($env_python -c "from math import floor; tmp = floor($batches_per_epoch / $comm_rounds_per_global_epoch); x = 1 if tmp == 0 else tmp; y = floor((($batches_per_epoch / $comm_rounds_per_global_epoch)/x)*$iterations); print($iterations if y<$iterations else y)") +echo batches per communication round: $batches_per_comm_round +echo corrected iterations: $new_iterations +test_after=10 #$(($new_iterations / $global_epochs)) +echo test after: $test_after +for i in "${tests[@]}" +do + for seed in "${random_seeds[@]}" + do + echo $i + IFS='_' read -ra NAMES <<< $i + IFS='.' read -ra NAME <<< ${NAMES[-1]} + log_dir_base=$nfs_home$logs_subfolder/${NAME[0]}:lr=$lr:r=$comm_rounds_per_global_epoch:b=$batchsize:$(date '+%Y-%m-%dT%H:%M') + echo results are stored in: $log_dir_base + log_dir=$log_dir_base/machine0 + mkdir -p $log_dir + weight_store_dir=$log_dir_base/weights + mkdir -p $weight_store_dir + cp $i $config_file + # changing the config files to reflect the values of the current grid search state + $python_bin/crudini --set $config_file COMMUNICATION addresses_filepath $ip_machines + $python_bin/crudini --set $config_file OPTIMIZER_PARAMS lr $lr + $python_bin/crudini --set $config_file TRAIN_PARAMS rounds $batches_per_comm_round + $python_bin/crudini --set $config_file TRAIN_PARAMS batch_size $batchsize + $python_bin/crudini --set $config_file DATASET random_seed $seed + + $env_python -q -X faulthandler $eval_file -ro 0 -tea $test_after -ld $log_dir -wsd $weight_store_dir -mid 0 -ps $procs_per_machine -ms $machines -is $new_iterations -gf $graph -ta $test_after -cf $config_file -ll $log_level + echo $i is done + sleep 10 + echo end of sleep + done +done +# \ No newline at end of file diff --git a/eval/run_xtimes_reddit_local2.sh b/eval/run_xtimes_reddit_local2.sh new file mode 100755 index 0000000000000000000000000000000000000000..9751bdc4be68521d3a00437cc0cf5798a33f6db9 --- /dev/null +++ b/eval/run_xtimes_reddit_local2.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# Documentation +# This bash file takes three inputs. The first argument (nfs_home) is the path to the nfs home directory. +# The second one (python_bin) is the path to the python bin folder. +# The last argument (logs_subfolder) is the path to the logs folder with respect to the nfs home directory. +# +# The nfs home directory should contain the code of this framework stored in $nfs_home/decentralizepy and a folder +# called configs which contains the file 'ip_addr_6Machines.json' +# The python bin folder needs to include all the dependencies of this project including crudini. +# The results will be stored in $nfs_home/$logs_subfolder +# Each of the experiments will be stored in its own folder inside the logs_subfolder. The folder of the experiment +# starts with the last part of the config name, i.e., for 'config_celeba_topkacc.ini' it will start with topkacc. +# The name further includes the learning rate, rounds and batchsize as well as the exact date at which the experiment +# was run. +# Example: ./run_grid.sh /mnt/nfs/wigger /mnt/nfs/wigger/anaconda3/envs/sacs39/bin /logs/celeba +# +# Additional requirements: +# Each node needs a folder called 'tmp' in the user's home directory +# +# Note: +# - The script does not change the optimizer. All configs are writen to use SGD. +# - The script will set '--test_after' and '--train_evaluate_after' such that it happens at the end of a global epoch. +# - The '--reset_optimizer' option is set to 0, i.e., the optimizer is not reset after a communication round (only +# relevant for Adams and other optimizers with internal state) +# +# Addapting the script to other datasets: +# Change the variable 'dataset_size' to reflect the data sets size. +# +# Known issues: +# - If the script is started at the very end of a minute then there is a change that two folders are created as not all +# machines may start running the script at the exact same moment. + +nfs_home=/tmp/logs/ +python_bin=/home/jeffrey/anaconda3/envs/sacs39/bin +logs_subfolder=reddit_local/ + +env_python=$python_bin/python3 +graph=16_regular.edges +config_file=~/tmp/config.ini +procs_per_machine=16 +machines=1 +global_epochs=2 +eval_file=testing.py +log_level=INFO + +ip_machines=ip_addr_1Machines.json + +m=`cat $ip_machines | grep $(/sbin/ifconfig ens785 | grep 'inet ' | awk '{print $2}') | cut -d'"' -f2` + +# Base configs for which the gird search is done +tests=("step_configs/config_reddit_topkacc_local.ini") # config_reddit_sharing_local.ini") # config_reddit_subsampling_local.ini") # +# Learning rates +lr="1" +# Batch size +batchsize="16" +# The number of communication rounds per global epoch +comm_rounds_per_global_epoch="10" +procs=`expr $procs_per_machine \* $machines` +echo procs: $procs +# Celeba has 63741 samples +# Reddit has 70642 +# Femnist 734463 +# Shakespeares 3678451 +dataset_size=70642 +# Calculating the number of samples that each user/proc will have on average +samples_per_user=`expr $dataset_size / $procs` +echo samples per user: $samples_per_user + +# random_seeds for which to rerun the experiments +random_seeds=("97") +# random_seed = 97 +echo batchsize: $batchsize +echo communication rounds per global epoch: $comm_rounds_per_global_epoch +# calculating how many batches there are in a global epoch for each user/proc +batches_per_epoch=$(($samples_per_user / $batchsize)) +echo batches per global epoch: $batches_per_epoch +# the number of iterations in 25 global epochs +iterations=$($env_python -c "from math import floor; print($batches_per_epoch * $global_epochs) if $comm_rounds_per_global_epoch >= $batches_per_epoch else print($global_epochs * $comm_rounds_per_global_epoch)") +echo iterations: $iterations +# calculating the number of batches each user/proc uses per communication step (The actual number may be a float, which we round down) +batches_per_comm_round=$($env_python -c "from math import floor; x = floor($batches_per_epoch / $comm_rounds_per_global_epoch); print(1 if x==0 else x)") +# since the batches per communication round were rounded down we need to change the number of iterations to reflect that +new_iterations=$($env_python -c "from math import floor; tmp = floor($batches_per_epoch / $comm_rounds_per_global_epoch); x = 1 if tmp == 0 else tmp; y = floor((($batches_per_epoch / $comm_rounds_per_global_epoch)/x)*$iterations); print($iterations if y<$iterations else y)") +echo batches per communication round: $batches_per_comm_round +echo corrected iterations: $new_iterations +test_after=$(($new_iterations / $global_epochs)) +echo test after: $test_after +for i in "${tests[@]}" +do + for seed in "${random_seeds[@]}" + do + echo $i + IFS='_' read -ra NAMES <<< $i + IFS='.' read -ra NAME <<< ${NAMES[-1]} + log_dir_base=$nfs_home$logs_subfolder/${NAME[0]}:lr=$lr:r=$comm_rounds_per_global_epoch:b=$batchsize:$(date '+%Y-%m-%dT%H:%M') + echo results are stored in: $log_dir_base + log_dir=$log_dir_base/machine0 + mkdir -p $log_dir + weight_store_dir=$log_dir_base/weights + mkdir -p $weight_store_dir + cp $i $config_file + # changing the config files to reflect the values of the current grid search state + $python_bin/crudini --set $config_file COMMUNICATION addresses_filepath $ip_machines + $python_bin/crudini --set $config_file OPTIMIZER_PARAMS lr $lr + $python_bin/crudini --set $config_file TRAIN_PARAMS rounds $batches_per_comm_round + $python_bin/crudini --set $config_file TRAIN_PARAMS batch_size $batchsize + $python_bin/crudini --set $config_file DATASET random_seed $seed + $env_python $eval_file -ro 0 -tea $test_after -ld $log_dir -wsd $weight_store_dir -mid 0 -ps $procs_per_machine -ms $machines -is $new_iterations -gf $graph -ta $test_after -cf $config_file -ll $log_level + echo $i is done + sleep 10 + echo end of sleep + done +done +# \ No newline at end of file diff --git a/eval/step_configs/config_reddit_jwins_local.ini b/eval/step_configs/config_reddit_jwins_local.ini new file mode 100644 index 0000000000000000000000000000000000000000..90ad9d25348a1170c1c8f12f88b7fc6b99be663d --- /dev/null +++ b/eval/step_configs/config_reddit_jwins_local.ini @@ -0,0 +1,43 @@ +[DATASET] +dataset_package = decentralizepy.datasets.Reddit +dataset_class = Reddit +random_seed = 97 +model_class = RNN +train_dir = /home/jeffrey/Downloads/reddit/per_user_data/train +test_dir = /home/jeffrey/Downloads/reddit/new_small_data/test +; python list of fractions below +sizes = + +[OPTIMIZER_PARAMS] +optimizer_package = torch.optim +optimizer_class = SGD +lr = 0.001 + +[TRAIN_PARAMS] +training_package = decentralizepy.training.Training +training_class = Training +rounds = 47 +full_epochs = False +batch_size = 16 +shuffle = True +loss_package = torch.nn +loss_class = CrossEntropyLoss + +[COMMUNICATION] +comm_package = decentralizepy.communication.TCP +comm_class = TCP +addresses_filepath = ip_addr_6Machines.json +compression_package = decentralizepy.compression.EliasFpzipLossy +compression_class = EliasFpzipLossy +compress = False + +[SHARING] +sharing_package = decentralizepy.sharing.RandomAlphaWavelet +sharing_class = RandomAlpha +change_based_selection = True +alpha_list = [0.1,0.15,0.2,0.25,0.3,0.4,1.0] +wavelet=sym2 +level= 4 +accumulation = True +accumulate_averaging_changes = True +metadata_cap = 0.5 \ No newline at end of file diff --git a/eval/step_configs/config_reddit_sharing_local2.ini b/eval/step_configs/config_reddit_sharing_local2.ini new file mode 100644 index 0000000000000000000000000000000000000000..6a8a2eba40642f6df3d5c30cd7489554ca8bb080 --- /dev/null +++ b/eval/step_configs/config_reddit_sharing_local2.ini @@ -0,0 +1,36 @@ +[DATASET] +dataset_package = decentralizepy.datasets.Reddit +dataset_class = Reddit +random_seed = 97 +model_class = RNN +train_dir = /home/jeffrey/Downloads/reddit/per_user_data/train +test_dir = /home/jeffrey/Downloads/reddit/new_small_data/test +; python list of fractions below +sizes = + +[OPTIMIZER_PARAMS] +optimizer_package = torch.optim +optimizer_class = SGD +lr = 0.001 + +[TRAIN_PARAMS] +training_package = decentralizepy.training.Training +training_class = Training +rounds = 47 +full_epochs = False +batch_size = 16 +shuffle = True +loss_package = torch.nn +loss_class = CrossEntropyLoss + +[COMMUNICATION] +comm_package = decentralizepy.communication.TCP +comm_class = TCP +addresses_filepath = ip_addr_6Machines.json +compression_package = decentralizepy.compression.Elias +compression_class = Elias +compress = False + +[SHARING] +sharing_package = decentralizepy.sharing.Sharing +sharing_class = Sharing diff --git a/eval/step_configs/config_reddit_topkacc_local.ini b/eval/step_configs/config_reddit_topkacc_local.ini new file mode 100644 index 0000000000000000000000000000000000000000..8841ba40be85af8afab59dcc9958b3b787ac577b --- /dev/null +++ b/eval/step_configs/config_reddit_topkacc_local.ini @@ -0,0 +1,51 @@ +[DATASET] +dataset_package = decentralizepy.datasets.Reddit +dataset_class = Reddit +random_seed = 97 +model_class = RNN +train_dir = /home/jeffrey/Downloads/reddit/per_user_data/train +test_dir = /home/jeffrey/Downloads/reddit/new_small_data/test +; python list of fractions below +sizes = + +[OPTIMIZER_PARAMS] +optimizer_package = torch.optim +optimizer_class = SGD +lr = 0.001 + +[TRAIN_PARAMS] +training_package = decentralizepy.training.Training +training_class = Training +rounds = 47 +full_epochs = False +batch_size = 16 +shuffle = True +loss_package = torch.nn +loss_class = CrossEntropyLoss + +[COMMUNICATION] +comm_package = decentralizepy.communication.TCP +comm_class = TCP +addresses_filepath = ip_addr_6Machines.json +compression_package = decentralizepy.compression.Eliaszfplossy1 +compression_class = Eliaszfplossy1 +compress = True + +[SHARING] +sharing_package = decentralizepy.sharing.WaveletBound +sharing_class = WaveletBound +alpha=0.1 +lower_bound=0.1 +metro_hastings=True +;sharing_package = decentralizepy.sharing.PartialModel +;sharing_class = PartialModel +;alpha = 0.1 +;accumulation = True +;accumulate_averaging_changes = True +;sharing_package = decentralizepy.sharing.RandomAlphaWavelet +;sharing_class = RandomAlpha +;change_based_selection = True +;wavelet=sym2 +;level= 4 +;accumulation = True +;accumulate_averaging_changes = True \ No newline at end of file diff --git a/random files/16_regular.edges b/random files/16_regular.edges new file mode 100644 index 0000000000000000000000000000000000000000..4e847b9534add5352272851013ac3c1994f09b43 --- /dev/null +++ b/random files/16_regular.edges @@ -0,0 +1,49 @@ +16 +0 1 +0 3 +0 15 +1 0 +1 10 +1 2 +2 1 +2 3 +2 15 +3 0 +3 2 +3 4 +4 9 +4 3 +4 5 +5 4 +5 13 +5 6 +6 11 +6 5 +6 7 +7 8 +7 14 +7 6 +8 9 +8 12 +8 7 +9 8 +9 10 +9 4 +10 1 +10 11 +10 9 +11 10 +11 12 +11 6 +12 8 +12 11 +12 13 +13 12 +13 5 +13 14 +14 15 +14 13 +14 7 +15 0 +15 2 +15 14 diff --git a/random files/16_regular.png b/random files/16_regular.png new file mode 100644 index 0000000000000000000000000000000000000000..d9b3acd3227cbb311a5e2da33bfb56138f52d887 Binary files /dev/null and b/random files/16_regular.png differ diff --git a/random files/16_ring.edges b/random files/16_ring.edges new file mode 100644 index 0000000000000000000000000000000000000000..f94b76a8a0b04c2c93def6590acf53c90da514c7 --- /dev/null +++ b/random files/16_ring.edges @@ -0,0 +1,33 @@ +16 +0 1 +0 15 +1 0 +1 2 +2 1 +2 3 +3 2 +3 4 +4 3 +4 5 +5 4 +5 6 +6 5 +6 7 +7 8 +7 6 +8 9 +8 7 +9 8 +9 10 +10 9 +10 11 +11 10 +11 12 +12 11 +12 13 +13 12 +13 14 +14 13 +14 15 +15 0 +15 14 diff --git a/random files/16_ring.png b/random files/16_ring.png new file mode 100644 index 0000000000000000000000000000000000000000..2a5f1cce138624fa76a06028f8fa4f6d63d6439a Binary files /dev/null and b/random files/16_ring.png differ diff --git a/random files/192_regular.edges b/random files/192_regular.edges new file mode 100644 index 0000000000000000000000000000000000000000..71162a775d3ac2f7e0ed2e0965d307b059f4e0e9 --- /dev/null +++ b/random files/192_regular.edges @@ -0,0 +1,961 @@ +192 +0 129 +0 33 +0 3 +0 113 +0 178 +1 98 +1 132 +1 12 +1 186 +1 59 +2 80 +2 147 +2 53 +2 55 +2 189 +3 0 +3 36 +3 109 +3 111 +3 176 +4 104 +4 42 +4 86 +4 185 +4 27 +5 21 +5 157 +5 123 +5 125 +5 63 +6 41 +6 171 +6 48 +6 58 +6 189 +7 32 +7 105 +7 171 +7 176 +7 126 +8 96 +8 65 +8 140 +8 54 +8 25 +9 91 +9 13 +9 83 +9 184 +9 27 +10 44 +10 13 +10 14 +10 79 +10 157 +11 160 +11 132 +11 142 +11 80 +11 158 +12 1 +12 134 +12 147 +12 85 +12 188 +13 66 +13 9 +13 10 +13 185 +13 127 +14 169 +14 10 +14 55 +14 92 +14 126 +15 103 +15 104 +15 170 +15 112 +15 17 +16 138 +16 141 +16 143 +16 149 +16 157 +17 35 +17 37 +17 15 +17 144 +17 190 +18 160 +18 35 +18 102 +18 186 +18 63 +19 78 +19 48 +19 183 +19 60 +19 191 +20 130 +20 133 +20 180 +20 117 +20 118 +21 164 +21 5 +21 135 +21 179 +21 117 +22 100 +22 108 +22 89 +22 60 +22 30 +23 132 +23 168 +23 170 +23 107 +23 110 +24 66 +24 45 +24 80 +24 26 +24 62 +25 96 +25 8 +25 110 +25 82 +25 182 +26 97 +26 163 +26 48 +26 24 +26 127 +27 4 +27 9 +27 78 +27 112 +27 62 +28 138 +28 107 +28 111 +28 176 +28 122 +29 36 +29 172 +29 79 +29 146 +29 89 +30 130 +30 78 +30 22 +30 87 +30 123 +31 64 +31 101 +31 172 +31 175 +31 50 +32 7 +32 73 +32 41 +32 113 +32 188 +33 0 +33 131 +33 145 +33 115 +33 116 +34 163 +34 100 +34 142 +34 56 +34 88 +35 99 +35 165 +35 17 +35 18 +35 191 +36 3 +36 37 +36 74 +36 114 +36 29 +37 129 +37 36 +37 109 +37 47 +37 17 +38 98 +38 136 +38 169 +38 111 +38 51 +39 162 +39 82 +39 83 +39 182 +39 91 +40 160 +40 99 +40 110 +40 82 +40 184 +41 32 +41 6 +41 135 +41 106 +41 94 +42 4 +42 71 +42 172 +42 145 +42 61 +43 167 +43 113 +43 181 +43 85 +43 151 +44 129 +44 166 +44 169 +44 10 +44 146 +45 130 +45 46 +45 85 +45 181 +45 24 +46 129 +46 45 +46 174 +46 180 +46 158 +47 128 +47 37 +47 141 +47 115 +47 84 +48 131 +48 6 +48 177 +48 19 +48 26 +49 177 +49 147 +49 118 +49 55 +49 58 +50 128 +50 165 +50 183 +50 56 +50 31 +51 38 +51 141 +51 80 +51 119 +51 90 +52 107 +52 175 +52 114 +52 184 +52 92 +53 129 +53 2 +53 176 +53 84 +53 63 +54 69 +54 8 +54 173 +54 181 +54 185 +55 2 +55 166 +55 14 +55 49 +55 88 +56 34 +56 78 +56 50 +56 150 +56 156 +57 69 +57 101 +57 173 +57 120 +57 122 +58 164 +58 6 +58 142 +58 49 +58 187 +59 1 +59 77 +59 174 +59 143 +59 114 +60 161 +60 71 +60 167 +60 19 +60 22 +61 70 +61 72 +61 42 +61 75 +61 77 +62 180 +62 24 +62 27 +62 125 +62 63 +63 65 +63 5 +63 18 +63 53 +63 62 +64 98 +64 163 +64 144 +64 89 +64 31 +65 100 +65 8 +65 148 +65 182 +65 63 +66 132 +66 68 +66 13 +66 87 +66 24 +67 133 +67 137 +67 76 +67 118 +67 154 +68 128 +68 66 +68 164 +68 171 +68 117 +69 171 +69 172 +69 85 +69 54 +69 57 +70 131 +70 79 +70 81 +70 186 +70 61 +71 131 +71 134 +71 42 +71 138 +71 60 +72 133 +72 104 +72 175 +72 145 +72 61 +73 32 +73 103 +73 145 +73 116 +73 153 +74 99 +74 36 +74 183 +74 155 +74 159 +75 165 +75 143 +75 185 +75 61 +75 158 +76 96 +76 67 +76 174 +76 178 +76 120 +77 103 +77 141 +77 90 +77 59 +77 61 +78 139 +78 19 +78 56 +78 27 +78 30 +79 162 +79 70 +79 10 +79 120 +79 29 +80 2 +80 11 +80 51 +80 24 +80 190 +81 70 +81 134 +81 141 +81 153 +81 189 +82 39 +82 40 +82 137 +82 135 +82 25 +83 39 +83 9 +83 86 +83 154 +83 94 +84 102 +84 105 +84 47 +84 53 +84 121 +85 69 +85 104 +85 43 +85 12 +85 45 +86 4 +86 133 +86 144 +86 83 +86 180 +87 66 +87 144 +87 146 +87 30 +87 159 +88 128 +88 34 +88 139 +88 55 +88 91 +89 64 +89 22 +89 151 +89 184 +89 29 +90 77 +90 173 +90 51 +90 156 +90 190 +91 39 +91 9 +91 151 +91 88 +91 188 +92 121 +92 131 +92 14 +92 52 +92 185 +93 161 +93 168 +93 143 +93 176 +93 182 +94 162 +94 166 +94 167 +94 41 +94 83 +95 130 +95 163 +95 105 +95 111 +95 117 +96 8 +96 139 +96 76 +96 25 +96 155 +97 162 +97 137 +97 147 +97 181 +97 26 +98 64 +98 1 +98 38 +98 152 +98 158 +99 35 +99 164 +99 40 +99 74 +99 142 +100 65 +100 34 +100 179 +100 22 +100 189 +101 110 +101 148 +101 57 +101 124 +101 31 +102 106 +102 114 +102 18 +102 148 +102 84 +103 104 +103 73 +103 109 +103 77 +103 15 +104 4 +104 103 +104 72 +104 15 +104 85 +105 7 +105 106 +105 177 +105 84 +105 95 +106 102 +106 41 +106 105 +106 172 +106 150 +107 23 +107 52 +107 183 +107 28 +107 191 +108 130 +108 134 +108 22 +108 120 +108 155 +109 3 +109 37 +109 103 +109 173 +109 149 +110 101 +110 40 +110 23 +110 25 +110 126 +111 3 +111 38 +111 116 +111 28 +111 95 +112 155 +112 174 +112 15 +112 27 +112 189 +113 160 +113 0 +113 32 +113 43 +113 115 +114 36 +114 102 +114 52 +114 150 +114 59 +115 33 +115 168 +115 136 +115 47 +115 113 +116 33 +116 73 +116 170 +116 111 +116 127 +117 68 +117 20 +117 21 +117 154 +117 95 +118 67 +118 140 +118 49 +118 20 +118 152 +119 174 +119 51 +119 149 +119 120 +119 187 +120 108 +120 76 +120 79 +120 119 +120 57 +121 162 +121 165 +121 170 +121 84 +121 92 +122 28 +122 180 +122 57 +122 187 +122 124 +123 5 +123 137 +123 30 +123 183 +123 190 +124 161 +124 101 +124 154 +124 140 +124 122 +125 5 +125 136 +125 177 +125 184 +125 62 +126 7 +126 173 +126 110 +126 175 +126 14 +127 135 +127 167 +127 13 +127 116 +127 26 +128 68 +128 47 +128 50 +128 88 +128 157 +129 0 +129 37 +129 44 +129 46 +129 53 +130 108 +130 45 +130 20 +130 30 +130 95 +131 33 +131 70 +131 71 +131 48 +131 92 +132 1 +132 66 +132 11 +132 23 +132 156 +133 67 +133 72 +133 148 +133 20 +133 86 +134 166 +134 71 +134 108 +134 12 +134 81 +135 41 +135 178 +135 82 +135 21 +135 127 +136 165 +136 38 +136 115 +136 125 +136 159 +137 97 +137 161 +137 67 +137 82 +137 123 +138 71 +138 16 +138 146 +138 182 +138 28 +139 96 +139 78 +139 150 +139 88 +139 153 +140 8 +140 124 +140 118 +140 153 +140 188 +141 77 +141 47 +141 16 +141 81 +141 51 +142 34 +142 99 +142 11 +142 151 +142 58 +143 75 +143 16 +143 186 +143 59 +143 93 +144 64 +144 171 +144 17 +144 86 +144 87 +145 33 +145 72 +145 73 +145 42 +145 153 +146 138 +146 44 +146 178 +146 87 +146 29 +147 97 +147 2 +147 166 +147 12 +147 49 +148 65 +148 133 +148 101 +148 102 +148 191 +149 164 +149 168 +149 109 +149 16 +149 119 +150 106 +150 139 +150 175 +150 114 +150 56 +151 168 +151 43 +151 142 +151 89 +151 91 +152 161 +152 98 +152 118 +152 154 +152 187 +153 73 +153 139 +153 140 +153 81 +153 145 +154 67 +154 83 +154 117 +154 152 +154 124 +155 96 +155 74 +155 108 +155 112 +155 190 +156 132 +156 169 +156 181 +156 56 +156 90 +157 128 +157 163 +157 5 +157 10 +157 16 +158 98 +158 75 +158 11 +158 46 +158 178 +159 160 +159 136 +159 74 +159 179 +159 87 +160 40 +160 11 +160 113 +160 18 +160 159 +161 137 +161 60 +161 152 +161 124 +161 93 +162 97 +162 39 +162 79 +162 121 +162 94 +163 64 +163 34 +163 26 +163 157 +163 95 +164 99 +164 68 +164 21 +164 149 +164 58 +165 35 +165 136 +165 75 +165 50 +165 121 +166 134 +166 44 +166 147 +166 55 +166 94 +167 170 +167 43 +167 60 +167 94 +167 127 +168 115 +168 23 +168 149 +168 151 +168 93 +169 38 +169 44 +169 14 +169 179 +169 156 +170 167 +170 15 +170 116 +170 23 +170 121 +171 68 +171 69 +171 6 +171 7 +171 144 +172 69 +172 42 +172 106 +172 29 +172 31 +173 109 +173 54 +173 57 +173 90 +173 126 +174 76 +174 46 +174 112 +174 119 +174 59 +175 72 +175 52 +175 150 +175 126 +175 31 +176 3 +176 7 +176 53 +176 28 +176 93 +177 105 +177 48 +177 49 +177 187 +177 125 +178 0 +178 135 +178 76 +178 146 +178 158 +179 100 +179 169 +179 21 +179 186 +179 159 +180 46 +180 20 +180 86 +180 122 +180 62 +181 97 +181 43 +181 45 +181 54 +181 156 +182 65 +182 39 +182 138 +182 25 +182 93 +183 74 +183 107 +183 50 +183 19 +183 123 +184 40 +184 9 +184 52 +184 89 +184 125 +185 4 +185 75 +185 13 +185 54 +185 92 +186 1 +186 70 +186 143 +186 18 +186 179 +187 122 +187 177 +187 119 +187 152 +187 58 +188 32 +188 140 +188 12 +188 91 +188 191 +189 2 +189 100 +189 6 +189 112 +189 81 +190 155 +190 80 +190 17 +190 90 +190 123 +191 35 +191 107 +191 19 +191 148 +191 188 diff --git a/random files/192_regular.png b/random files/192_regular.png new file mode 100644 index 0000000000000000000000000000000000000000..ef86b2e34344d2b04e0df33d78ea4fb8c0cd1154 Binary files /dev/null and b/random files/192_regular.png differ diff --git a/random files/288_regular.edges b/random files/288_regular.edges new file mode 100644 index 0000000000000000000000000000000000000000..3c7c269b0483ff854d31272c6e556d1f22407327 --- /dev/null +++ b/random files/288_regular.edges @@ -0,0 +1,1441 @@ +288 +0 193 +0 196 +0 44 +0 50 +0 185 +1 164 +1 136 +1 244 +1 183 +1 63 +2 260 +2 46 +2 273 +2 51 +2 25 +3 259 +3 197 +3 39 +3 232 +3 60 +4 226 +4 268 +4 238 +4 284 +4 188 +5 43 +5 141 +5 240 +5 81 +5 211 +6 97 +6 101 +6 7 +6 76 +6 152 +7 33 +7 6 +7 38 +7 9 +7 287 +8 236 +8 241 +8 178 +8 252 +8 220 +9 7 +9 77 +9 272 +9 211 +9 190 +10 34 +10 266 +10 172 +10 175 +10 241 +11 165 +11 12 +11 210 +11 115 +11 219 +12 131 +12 11 +12 176 +12 183 +12 94 +13 212 +13 278 +13 217 +13 187 +13 223 +14 261 +14 106 +14 141 +14 47 +14 280 +15 258 +15 110 +15 208 +15 119 +15 30 +16 139 +16 173 +16 83 +16 59 +16 125 +17 169 +17 50 +17 18 +17 212 +17 180 +18 163 +18 108 +18 17 +18 242 +18 281 +19 66 +19 26 +19 261 +19 218 +19 220 +20 160 +20 35 +20 174 +20 270 +20 253 +21 171 +21 205 +21 51 +21 55 +21 185 +22 264 +22 268 +22 117 +22 23 +22 91 +23 201 +23 271 +23 22 +23 190 +23 94 +24 163 +24 69 +24 168 +24 139 +24 215 +25 65 +25 2 +25 123 +25 125 +25 127 +26 162 +26 45 +26 177 +26 113 +26 19 +27 225 +27 98 +27 163 +27 48 +27 146 +28 160 +28 100 +28 164 +28 133 +28 85 +29 64 +29 229 +29 199 +29 211 +29 221 +30 39 +30 270 +30 15 +30 273 +30 189 +31 164 +31 166 +31 199 +31 103 +31 46 +32 64 +32 256 +32 104 +32 144 +32 156 +33 7 +33 266 +33 186 +33 221 +33 158 +34 230 +34 10 +34 115 +34 148 +34 286 +35 160 +35 168 +35 20 +35 91 +35 222 +36 133 +36 198 +36 239 +36 146 +36 218 +37 162 +37 92 +37 153 +37 123 +37 188 +38 198 +38 7 +38 76 +38 206 +38 120 +39 3 +39 101 +39 266 +39 282 +39 30 +40 194 +40 71 +40 111 +40 239 +40 148 +41 105 +41 78 +41 250 +41 253 +41 190 +42 239 +42 114 +42 115 +42 214 +42 218 +43 5 +43 209 +43 246 +43 247 +43 94 +44 0 +44 234 +44 174 +44 117 +44 124 +45 213 +45 117 +45 247 +45 26 +45 62 +46 161 +46 2 +46 228 +46 252 +46 31 +47 197 +47 266 +47 14 +47 282 +47 251 +48 192 +48 67 +48 195 +48 143 +48 27 +49 116 +49 52 +49 182 +49 189 +49 94 +50 0 +50 259 +50 265 +50 269 +50 17 +51 2 +51 163 +51 70 +51 211 +51 21 +52 258 +52 68 +52 140 +52 49 +52 54 +53 200 +53 137 +53 108 +53 151 +53 56 +54 75 +54 208 +54 52 +54 221 +54 61 +55 73 +55 141 +55 148 +55 21 +55 189 +56 101 +56 233 +56 239 +56 53 +56 287 +57 136 +57 148 +57 218 +57 91 +57 156 +58 216 +58 89 +58 88 +58 156 +58 93 +59 256 +59 197 +59 173 +59 16 +59 149 +60 3 +60 103 +60 83 +60 214 +60 157 +61 230 +61 264 +61 243 +61 54 +61 152 +62 224 +62 65 +62 45 +62 173 +62 84 +63 1 +63 228 +63 105 +63 75 +63 271 +64 32 +64 137 +64 147 +64 121 +64 29 +65 76 +65 276 +65 25 +65 62 +65 191 +66 167 +66 19 +66 275 +66 118 +66 126 +67 92 +67 48 +67 121 +67 124 +67 125 +68 200 +68 204 +68 52 +68 118 +68 156 +69 235 +69 215 +69 24 +69 249 +69 159 +70 202 +70 267 +70 106 +70 240 +70 51 +71 226 +71 135 +71 40 +71 167 +71 241 +72 161 +72 231 +72 151 +72 280 +72 287 +73 258 +73 269 +73 207 +73 55 +73 90 +74 174 +74 209 +74 210 +74 119 +74 284 +75 166 +75 79 +75 54 +75 279 +75 63 +76 65 +76 227 +76 6 +76 38 +76 215 +77 231 +77 9 +77 183 +77 154 +77 127 +78 224 +78 100 +78 41 +78 157 +78 223 +79 262 +79 104 +79 75 +79 206 +79 215 +80 257 +80 260 +80 236 +80 277 +80 154 +81 224 +81 194 +81 5 +81 230 +81 282 +82 265 +82 147 +82 150 +82 280 +82 90 +83 225 +83 16 +83 184 +83 122 +83 60 +84 99 +84 262 +84 105 +84 120 +84 62 +85 244 +85 151 +85 121 +85 122 +85 28 +86 226 +86 233 +86 201 +86 207 +86 120 +87 192 +87 199 +87 146 +87 123 +87 222 +88 106 +88 144 +88 114 +88 275 +88 58 +89 99 +89 180 +89 276 +89 58 +89 223 +90 73 +90 177 +90 82 +90 186 +90 126 +91 35 +91 140 +91 173 +91 22 +91 57 +92 67 +92 99 +92 37 +92 274 +92 283 +93 263 +93 277 +93 58 +93 253 +93 191 +94 195 +94 43 +94 12 +94 49 +94 23 +95 132 +95 103 +95 140 +95 179 +95 149 +96 188 +96 116 +96 281 +96 251 +96 124 +97 166 +97 167 +97 6 +97 233 +97 172 +98 128 +98 233 +98 279 +98 185 +98 27 +99 242 +99 84 +99 246 +99 89 +99 92 +100 78 +100 272 +100 183 +100 247 +100 28 +101 6 +101 39 +101 236 +101 143 +101 56 +102 129 +102 195 +102 200 +102 264 +102 178 +103 137 +103 31 +103 60 +103 95 +103 159 +104 224 +104 32 +104 235 +104 79 +104 220 +105 41 +105 108 +105 84 +105 63 +105 255 +106 70 +106 14 +106 88 +106 250 +106 157 +107 166 +107 202 +107 270 +107 216 +107 121 +108 105 +108 138 +108 269 +108 18 +108 53 +109 165 +109 111 +109 275 +109 147 +109 245 +110 260 +110 235 +110 206 +110 15 +110 146 +111 259 +111 40 +111 138 +111 109 +111 254 +112 132 +112 235 +112 274 +112 178 +112 275 +113 154 +113 251 +113 217 +113 26 +113 155 +114 42 +114 118 +114 152 +114 153 +114 88 +115 160 +115 34 +115 42 +115 11 +115 236 +116 96 +116 194 +116 49 +116 122 +116 187 +117 44 +117 45 +117 207 +117 22 +117 223 +118 66 +118 196 +118 68 +118 231 +118 114 +119 74 +119 15 +119 212 +119 219 +119 127 +120 38 +120 176 +120 273 +120 84 +120 86 +121 64 +121 67 +121 107 +121 245 +121 85 +122 144 +122 83 +122 116 +122 85 +122 285 +123 128 +123 37 +123 87 +123 25 +123 158 +124 96 +124 67 +124 44 +124 208 +124 150 +125 67 +125 172 +125 16 +125 25 +125 189 +126 160 +126 66 +126 238 +126 90 +126 254 +127 203 +127 77 +127 119 +127 216 +127 25 +128 98 +128 139 +128 175 +128 248 +128 123 +129 132 +129 102 +129 264 +129 169 +129 158 +130 167 +130 237 +130 178 +130 217 +130 154 +131 133 +131 138 +131 203 +131 12 +131 147 +132 129 +132 199 +132 171 +132 112 +132 95 +133 131 +133 36 +133 219 +133 28 +133 221 +134 232 +134 137 +134 208 +134 278 +134 219 +135 71 +135 263 +135 204 +135 282 +135 284 +136 193 +136 1 +136 237 +136 57 +136 286 +137 64 +137 134 +137 103 +137 53 +137 182 +138 131 +138 202 +138 108 +138 111 +138 191 +139 128 +139 16 +139 212 +139 24 +139 189 +140 159 +140 52 +140 185 +140 91 +140 95 +141 5 +141 14 +141 55 +141 154 +141 191 +142 237 +142 238 +142 185 +142 221 +142 158 +143 257 +143 101 +143 232 +143 268 +143 48 +144 32 +144 225 +144 88 +144 249 +144 122 +145 164 +145 197 +145 229 +145 283 +145 188 +146 36 +146 110 +146 277 +146 87 +146 27 +147 64 +147 258 +147 131 +147 109 +147 82 +148 34 +148 40 +148 55 +148 57 +148 253 +149 228 +149 173 +149 246 +149 59 +149 95 +150 234 +150 82 +150 184 +150 186 +150 124 +151 72 +151 85 +151 53 +151 182 +151 155 +152 6 +152 114 +152 184 +152 61 +152 191 +153 37 +153 269 +153 210 +153 242 +153 114 +154 130 +154 77 +154 141 +154 80 +154 113 +155 261 +155 172 +155 113 +155 151 +155 286 +156 32 +156 68 +156 176 +156 57 +156 58 +157 106 +157 268 +157 78 +157 282 +157 60 +158 129 +158 33 +158 142 +158 177 +158 123 +159 69 +159 103 +159 268 +159 140 +159 209 +160 35 +160 115 +160 20 +160 28 +160 126 +161 163 +161 167 +161 72 +161 46 +161 219 +162 37 +162 232 +162 205 +162 26 +162 255 +163 161 +163 18 +163 51 +163 24 +163 27 +164 1 +164 271 +164 145 +164 28 +164 31 +165 225 +165 11 +165 109 +165 244 +165 182 +166 97 +166 266 +166 75 +166 107 +166 31 +167 161 +167 66 +167 130 +167 97 +167 71 +168 35 +168 238 +168 180 +168 213 +168 24 +169 129 +169 195 +169 17 +169 179 +169 243 +170 261 +170 197 +170 213 +170 248 +170 285 +171 256 +171 227 +171 132 +171 21 +171 181 +172 97 +172 10 +172 179 +172 155 +172 125 +173 91 +173 16 +173 149 +173 59 +173 62 +174 234 +174 74 +174 44 +174 20 +174 213 +175 128 +175 10 +175 206 +175 177 +175 190 +176 232 +176 12 +176 273 +176 120 +176 156 +177 90 +177 202 +177 175 +177 26 +177 158 +178 130 +178 102 +178 8 +178 207 +178 112 +179 169 +179 172 +179 210 +179 279 +179 95 +180 168 +180 205 +180 17 +180 181 +180 89 +181 196 +181 265 +181 171 +181 271 +181 180 +182 165 +182 137 +182 208 +182 49 +182 151 +183 1 +183 100 +183 12 +183 77 +183 244 +184 280 +184 240 +184 83 +184 150 +184 152 +185 0 +185 98 +185 140 +185 142 +185 21 +186 33 +186 245 +186 150 +186 90 +186 287 +187 13 +187 274 +187 243 +187 116 +187 216 +188 96 +188 4 +188 37 +188 145 +188 242 +189 139 +189 49 +189 55 +189 125 +189 30 +190 41 +190 9 +190 175 +190 23 +190 222 +191 65 +191 138 +191 141 +191 152 +191 93 +192 263 +192 48 +192 276 +192 87 +192 285 +193 0 +193 194 +193 262 +193 136 +193 252 +194 193 +194 195 +194 40 +194 81 +194 116 +195 194 +195 102 +195 169 +195 48 +195 94 +196 0 +196 204 +196 181 +196 118 +196 251 +197 3 +197 170 +197 47 +197 145 +197 59 +198 36 +198 38 +198 205 +198 245 +198 255 +199 132 +199 214 +199 87 +199 29 +199 31 +200 68 +200 102 +200 267 +200 272 +200 53 +201 227 +201 204 +201 274 +201 86 +201 23 +202 70 +202 138 +202 107 +202 177 +202 247 +203 131 +203 277 +203 284 +203 222 +203 127 +204 196 +204 68 +204 135 +204 201 +204 237 +205 257 +205 162 +205 198 +205 180 +205 21 +206 38 +206 262 +206 110 +206 79 +206 175 +207 73 +207 238 +207 178 +207 117 +207 86 +208 134 +208 15 +208 182 +208 54 +208 124 +209 74 +209 43 +209 239 +209 277 +209 159 +210 74 +210 11 +210 179 +210 246 +210 153 +211 5 +211 9 +211 51 +211 29 +211 255 +212 139 +212 13 +212 17 +212 278 +212 119 +213 168 +213 170 +213 45 +213 174 +213 245 +214 199 +214 42 +214 267 +214 60 +214 255 +215 69 +215 76 +215 79 +215 24 +215 223 +216 107 +216 279 +216 58 +216 187 +216 127 +217 130 +217 228 +217 13 +217 113 +217 244 +218 36 +218 42 +218 19 +218 276 +218 57 +219 161 +219 133 +219 134 +219 11 +219 119 +220 8 +220 104 +220 19 +220 278 +220 253 +221 33 +221 133 +221 142 +221 54 +221 29 +222 35 +222 203 +222 87 +222 251 +222 190 +223 13 +223 78 +223 117 +223 215 +223 89 +224 104 +224 269 +224 78 +224 81 +224 62 +225 165 +225 144 +225 83 +225 250 +225 27 +226 227 +226 4 +226 71 +226 86 +226 283 +227 226 +227 201 +227 234 +227 171 +227 76 +228 217 +228 46 +228 149 +228 281 +228 63 +229 256 +229 258 +229 231 +229 145 +229 29 +230 34 +230 259 +230 231 +230 81 +230 61 +231 229 +231 230 +231 72 +231 77 +231 118 +232 162 +232 3 +232 134 +232 143 +232 176 +233 97 +233 98 +233 86 +233 279 +233 56 +234 227 +234 44 +234 174 +234 150 +234 252 +235 69 +235 104 +235 110 +235 270 +235 112 +236 101 +236 8 +236 80 +236 115 +236 280 +237 130 +237 136 +237 204 +237 142 +237 272 +238 4 +238 168 +238 142 +238 207 +238 126 +239 36 +239 40 +239 42 +239 209 +239 56 +240 257 +240 5 +240 70 +240 241 +240 184 +241 71 +241 8 +241 10 +241 240 +241 278 +242 99 +242 18 +242 153 +242 283 +242 188 +243 169 +243 265 +243 187 +243 61 +243 254 +244 1 +244 165 +244 85 +244 183 +244 217 +245 198 +245 109 +245 213 +245 121 +245 186 +246 99 +246 43 +246 210 +246 149 +246 286 +247 100 +247 202 +247 43 +247 45 +247 284 +248 128 +248 170 +248 272 +248 254 +248 287 +249 259 +249 69 +249 144 +249 273 +249 281 +250 225 +250 264 +250 41 +250 106 +250 271 +251 96 +251 196 +251 47 +251 113 +251 222 +252 193 +252 8 +252 234 +252 46 +252 254 +253 41 +253 20 +253 148 +253 220 +253 93 +254 111 +254 243 +254 248 +254 252 +254 126 +255 162 +255 198 +255 105 +255 211 +255 214 +256 32 +256 261 +256 229 +256 171 +256 59 +257 260 +257 205 +257 143 +257 80 +257 240 +258 229 +258 73 +258 15 +258 147 +258 52 +259 3 +259 230 +259 111 +259 50 +259 249 +260 257 +260 2 +260 263 +260 110 +260 80 +261 256 +261 170 +261 14 +261 19 +261 155 +262 193 +262 206 +262 79 +262 84 +262 285 +263 192 +263 260 +263 135 +263 281 +263 93 +264 129 +264 102 +264 22 +264 250 +264 61 +265 267 +265 82 +265 243 +265 50 +265 181 +266 33 +266 166 +266 39 +266 10 +266 47 +267 70 +267 200 +267 265 +267 276 +267 214 +268 4 +268 143 +268 22 +268 157 +268 159 +269 224 +269 73 +269 108 +269 50 +269 153 +270 107 +270 235 +270 20 +270 285 +270 30 +271 164 +271 181 +271 23 +271 250 +271 63 +272 100 +272 200 +272 9 +272 237 +272 248 +273 2 +273 176 +273 120 +273 249 +273 30 +274 201 +274 187 +274 112 +274 283 +274 92 +275 66 +275 109 +275 112 +275 88 +275 286 +276 192 +276 65 +276 267 +276 89 +276 218 +277 203 +277 80 +277 209 +277 146 +277 93 +278 134 +278 13 +278 241 +278 212 +278 220 +279 98 +279 233 +279 75 +279 179 +279 216 +280 72 +280 236 +280 14 +280 82 +280 184 +281 96 +281 228 +281 263 +281 18 +281 249 +282 135 +282 39 +282 47 +282 81 +282 157 +283 226 +283 145 +283 274 +283 242 +283 92 +284 4 +284 135 +284 74 +284 203 +284 247 +285 192 +285 262 +285 170 +285 270 +285 122 +286 34 +286 136 +286 275 +286 246 +286 155 +287 7 +287 186 +287 72 +287 248 +287 56 diff --git a/random files/384_regular.edges b/random files/384_regular.edges new file mode 100644 index 0000000000000000000000000000000000000000..14b37745a27a4a1e04d6210169b296f5846569bc --- /dev/null +++ b/random files/384_regular.edges @@ -0,0 +1,2305 @@ +384 +0 42 +0 203 +0 174 +0 212 +0 180 +0 22 +1 271 +1 304 +1 272 +1 212 +1 25 +1 282 +2 256 +2 354 +2 21 +2 54 +2 152 +2 313 +3 268 +3 332 +3 211 +3 20 +3 150 +3 119 +4 10 +4 42 +4 332 +4 247 +4 91 +4 254 +5 199 +5 204 +5 237 +5 374 +5 376 +5 157 +6 352 +6 296 +6 379 +6 21 +6 280 +6 347 +7 288 +7 194 +7 293 +7 174 +7 54 +7 310 +8 103 +8 333 +8 143 +8 242 +8 50 +8 87 +9 41 +9 203 +9 301 +9 112 +9 180 +9 53 +10 130 +10 4 +10 172 +10 141 +10 334 +10 22 +11 265 +11 43 +11 79 +11 341 +11 245 +11 283 +12 67 +12 73 +12 123 +12 27 +12 124 +12 253 +13 160 +13 297 +13 171 +13 173 +13 308 +13 248 +14 358 +14 294 +14 302 +14 339 +14 24 +14 286 +15 129 +15 361 +15 309 +15 153 +15 380 +15 94 +16 199 +16 170 +16 77 +16 240 +16 180 +16 319 +17 65 +17 68 +17 324 +17 43 +17 211 +17 245 +18 324 +18 231 +18 140 +18 305 +18 86 +18 183 +19 200 +19 363 +19 83 +19 211 +19 310 +19 189 +20 192 +20 3 +20 341 +20 278 +20 314 +20 59 +21 2 +21 163 +21 197 +21 6 +21 348 +21 63 +22 0 +22 33 +22 229 +22 10 +22 142 +22 115 +23 322 +23 131 +23 290 +23 103 +23 171 +23 81 +24 226 +24 98 +24 110 +24 14 +24 305 +24 383 +25 1 +25 314 +25 206 +25 175 +25 176 +25 90 +26 167 +26 41 +26 273 +26 340 +26 379 +26 188 +27 34 +27 138 +27 363 +27 12 +27 317 +27 255 +28 320 +28 293 +28 234 +28 209 +28 210 +28 91 +29 325 +29 267 +29 151 +29 281 +29 220 +29 62 +30 193 +30 197 +30 166 +30 134 +30 46 +30 312 +31 225 +31 365 +31 109 +31 311 +31 216 +31 221 +32 96 +32 192 +32 266 +32 343 +32 156 +32 381 +33 290 +33 35 +33 73 +33 43 +33 22 +33 319 +34 140 +34 366 +34 308 +34 183 +34 27 +34 62 +35 33 +35 333 +35 276 +35 215 +35 344 +35 314 +36 258 +36 336 +36 82 +36 254 +36 62 +36 127 +37 195 +37 43 +37 175 +37 337 +37 127 +37 319 +38 353 +38 264 +38 137 +38 305 +38 52 +38 380 +39 352 +39 268 +39 371 +39 181 +39 281 +39 252 +40 197 +40 168 +40 369 +40 243 +40 277 +40 315 +41 353 +41 257 +41 26 +41 9 +41 372 +41 186 +42 0 +42 323 +42 4 +42 82 +42 309 +42 94 +43 33 +43 37 +43 11 +43 303 +43 17 +43 350 +44 288 +44 261 +44 72 +44 367 +44 372 +44 119 +45 224 +45 198 +45 136 +45 143 +45 373 +45 158 +46 382 +46 60 +46 213 +46 156 +46 30 +46 351 +47 194 +47 259 +47 101 +47 294 +47 302 +47 272 +48 96 +48 297 +48 265 +48 153 +48 155 +48 61 +49 66 +49 205 +49 141 +49 113 +49 53 +49 149 +50 8 +50 201 +50 240 +50 117 +50 92 +50 95 +51 256 +51 265 +51 81 +51 147 +51 183 +51 121 +52 131 +52 38 +52 141 +52 272 +52 115 +52 315 +53 9 +53 203 +53 365 +53 49 +53 178 +53 91 +54 129 +54 2 +54 100 +54 7 +54 154 +54 283 +55 227 +55 131 +55 72 +55 138 +55 204 +55 188 +56 103 +56 266 +56 107 +56 171 +56 109 +56 371 +57 232 +57 108 +57 212 +57 217 +57 378 +57 316 +58 69 +58 209 +58 242 +58 221 +58 94 +58 223 +59 258 +59 361 +59 239 +59 147 +59 20 +59 188 +60 261 +60 205 +60 46 +60 271 +60 147 +60 222 +61 325 +61 167 +61 363 +61 48 +61 308 +61 281 +62 34 +62 36 +62 334 +62 304 +62 377 +62 29 +63 100 +63 176 +63 21 +63 309 +63 285 +63 253 +64 164 +64 334 +64 280 +64 250 +64 219 +64 94 +65 224 +65 172 +65 305 +65 17 +65 92 +65 157 +66 97 +66 137 +66 49 +66 180 +66 345 +66 282 +67 170 +67 12 +67 237 +67 84 +67 344 +67 93 +68 323 +68 163 +68 17 +68 86 +68 379 +68 124 +69 97 +69 202 +69 210 +69 147 +69 58 +69 188 +70 231 +70 274 +70 248 +70 220 +70 350 +70 286 +71 230 +71 102 +71 326 +71 330 +71 216 +71 287 +72 96 +72 321 +72 167 +72 44 +72 55 +72 351 +73 96 +73 33 +73 101 +73 12 +73 149 +73 377 +74 102 +74 295 +74 172 +74 183 +74 280 +74 120 +75 321 +75 165 +75 246 +75 278 +75 376 +75 126 +76 348 +76 158 +76 252 +76 253 +76 190 +76 127 +77 224 +77 132 +77 368 +77 16 +77 114 +77 181 +78 322 +78 236 +78 206 +78 366 +78 377 +78 156 +79 231 +79 328 +79 11 +79 277 +79 85 +79 282 +80 290 +80 135 +80 137 +80 238 +80 336 +80 343 +81 359 +81 110 +81 146 +81 51 +81 23 +81 279 +82 195 +82 36 +82 42 +82 274 +82 344 +82 250 +83 196 +83 232 +83 337 +83 19 +83 281 +83 382 +84 67 +84 166 +84 358 +84 335 +84 346 +84 255 +85 322 +85 79 +85 213 +85 218 +85 347 +85 189 +86 100 +86 68 +86 172 +86 18 +86 311 +86 92 +87 326 +87 8 +87 235 +87 112 +87 150 +87 90 +88 97 +88 268 +88 178 +88 146 +88 217 +88 187 +89 288 +89 97 +89 167 +89 107 +89 248 +89 286 +90 164 +90 87 +90 215 +90 120 +90 25 +90 285 +91 321 +91 4 +91 145 +91 53 +91 218 +91 28 +92 65 +92 50 +92 339 +92 86 +92 122 +92 381 +93 322 +93 67 +93 330 +93 206 +93 306 +93 249 +94 64 +94 295 +94 169 +94 42 +94 15 +94 58 +95 356 +95 263 +95 105 +95 50 +95 275 +95 249 +96 32 +96 72 +96 73 +96 48 +96 253 +96 159 +97 66 +97 324 +97 69 +97 367 +97 88 +97 89 +98 135 +98 168 +98 371 +98 24 +98 313 +98 158 +99 296 +99 298 +99 330 +99 146 +99 185 +99 122 +100 352 +100 54 +100 86 +100 282 +100 279 +100 63 +101 161 +101 327 +101 168 +101 73 +101 302 +101 47 +102 71 +102 74 +102 299 +102 204 +102 365 +102 380 +103 8 +103 241 +103 179 +103 23 +103 56 +103 154 +104 193 +104 164 +104 139 +104 115 +104 378 +104 349 +105 192 +105 166 +105 266 +105 205 +105 318 +105 95 +106 171 +106 332 +106 177 +106 244 +106 215 +106 126 +107 89 +107 260 +107 113 +107 311 +107 56 +107 377 +108 325 +108 210 +108 157 +108 57 +108 156 +108 285 +109 194 +109 355 +109 307 +109 56 +109 31 +109 383 +110 260 +110 261 +110 235 +110 241 +110 81 +110 24 +111 292 +111 138 +111 364 +111 276 +111 309 +111 188 +112 130 +112 168 +112 9 +112 87 +112 151 +112 316 +113 326 +113 107 +113 171 +113 269 +113 49 +113 219 +114 226 +114 234 +114 77 +114 208 +114 339 +114 314 +115 168 +115 104 +115 307 +115 52 +115 22 +115 119 +116 290 +116 227 +116 165 +116 357 +116 313 +116 317 +117 258 +117 166 +117 198 +117 298 +117 50 +117 221 +118 355 +118 262 +118 204 +118 173 +118 344 +118 153 +119 3 +119 44 +119 208 +119 369 +119 115 +119 341 +120 233 +120 74 +120 241 +120 342 +120 90 +120 315 +121 264 +121 232 +121 366 +121 335 +121 51 +121 190 +122 160 +122 99 +122 139 +122 381 +122 92 +122 189 +123 131 +123 329 +123 12 +123 300 +123 247 +123 313 +124 224 +124 68 +124 12 +124 333 +124 279 +124 222 +125 227 +125 358 +125 177 +125 372 +125 340 +125 351 +126 197 +126 263 +126 106 +126 75 +126 153 +126 318 +127 36 +127 37 +127 199 +127 76 +127 304 +127 287 +128 257 +128 162 +128 167 +128 206 +128 277 +128 287 +129 302 +129 15 +129 177 +129 244 +129 54 +129 316 +130 165 +130 327 +130 231 +130 10 +130 112 +130 210 +131 264 +131 297 +131 52 +131 23 +131 55 +131 123 +132 328 +132 267 +132 77 +132 375 +132 218 +132 253 +133 364 +133 334 +133 238 +133 241 +133 184 +133 189 +134 320 +134 259 +134 331 +134 367 +134 375 +134 30 +135 98 +135 293 +135 331 +135 80 +135 182 +135 383 +136 225 +136 45 +136 242 +136 243 +136 345 +136 223 +137 66 +137 291 +137 38 +137 80 +137 214 +137 221 +138 201 +138 266 +138 251 +138 111 +138 55 +138 27 +139 358 +139 104 +139 360 +139 272 +139 345 +139 122 +140 289 +140 34 +140 208 +140 18 +140 216 +140 254 +141 353 +141 327 +141 10 +141 49 +141 52 +141 213 +142 301 +142 365 +142 175 +142 277 +142 22 +142 278 +143 225 +143 8 +143 45 +143 207 +143 240 +143 351 +144 261 +144 333 +144 334 +144 369 +144 373 +144 222 +145 322 +145 170 +145 338 +145 154 +145 91 +145 220 +146 352 +146 99 +146 81 +146 306 +146 88 +146 221 +147 69 +147 267 +147 51 +147 216 +147 59 +147 60 +148 228 +148 269 +148 370 +148 212 +148 375 +148 159 +149 290 +149 197 +149 73 +149 297 +149 49 +149 283 +150 3 +150 326 +150 211 +150 87 +150 279 +150 314 +151 112 +151 274 +151 340 +151 374 +151 283 +151 29 +152 2 +152 196 +152 198 +152 264 +152 188 +152 350 +153 228 +153 15 +153 303 +153 48 +153 118 +153 126 +154 289 +154 103 +154 169 +154 145 +154 273 +154 54 +155 291 +155 355 +155 48 +155 305 +155 312 +155 345 +156 32 +156 163 +156 108 +156 46 +156 78 +156 383 +157 65 +157 5 +157 361 +157 362 +157 108 +157 312 +158 98 +158 325 +158 76 +158 45 +158 367 +158 213 +159 96 +159 230 +159 178 +159 148 +159 309 +159 380 +160 122 +160 328 +160 236 +160 13 +160 179 +160 186 +161 162 +161 101 +161 230 +161 370 +161 275 +161 246 +162 128 +162 161 +162 196 +162 181 +162 187 +162 220 +163 354 +163 68 +163 204 +163 370 +163 21 +163 156 +164 64 +164 104 +164 337 +164 90 +164 251 +164 254 +165 289 +165 130 +165 356 +165 75 +165 174 +165 116 +166 329 +166 105 +166 297 +166 84 +166 117 +166 30 +167 128 +167 72 +167 247 +167 89 +167 26 +167 61 +168 256 +168 98 +168 101 +168 40 +168 112 +168 115 +169 289 +169 294 +169 331 +169 94 +169 154 +169 190 +170 321 +170 67 +170 358 +170 16 +170 145 +170 274 +171 106 +171 13 +171 113 +171 342 +171 23 +171 56 +172 65 +172 202 +172 74 +172 10 +172 332 +172 86 +173 320 +173 198 +173 331 +173 13 +173 118 +173 377 +174 0 +174 165 +174 7 +174 267 +174 313 +174 350 +175 37 +175 142 +175 271 +175 248 +175 25 +175 187 +176 195 +176 228 +176 292 +176 239 +176 25 +176 63 +177 129 +177 106 +177 240 +177 241 +177 375 +177 125 +178 360 +178 233 +178 329 +178 53 +178 88 +178 159 +179 160 +179 192 +179 103 +179 231 +179 214 +179 285 +180 0 +180 66 +180 9 +180 271 +180 16 +180 247 +181 162 +181 195 +181 325 +181 39 +181 77 +181 278 +182 135 +182 233 +182 299 +182 335 +182 308 +182 183 +183 34 +183 74 +183 18 +183 51 +183 182 +183 184 +184 133 +184 295 +184 300 +184 367 +184 183 +184 347 +185 99 +185 355 +185 196 +185 230 +185 349 +185 222 +186 160 +186 262 +186 198 +186 264 +186 41 +186 270 +187 162 +187 261 +187 327 +187 234 +187 175 +187 88 +188 69 +188 111 +188 55 +188 152 +188 26 +188 59 +189 133 +189 199 +189 250 +189 19 +189 85 +189 122 +190 352 +190 169 +190 76 +190 121 +190 346 +190 283 +191 323 +191 357 +191 296 +191 336 +191 374 +191 286 +192 32 +192 105 +192 269 +192 179 +192 20 +192 348 +193 259 +193 104 +193 363 +193 245 +193 30 +193 254 +194 321 +194 7 +194 236 +194 109 +194 270 +194 47 +195 288 +195 37 +195 239 +195 176 +195 82 +195 181 +196 162 +196 293 +196 298 +196 83 +196 152 +196 185 +197 40 +197 208 +197 21 +197 149 +197 126 +197 30 +198 45 +198 173 +198 117 +198 152 +198 186 +198 284 +199 258 +199 5 +199 16 +199 376 +199 189 +199 127 +200 227 +200 236 +200 365 +200 302 +200 19 +200 280 +201 138 +201 298 +201 300 +201 50 +201 214 +201 378 +202 69 +202 299 +202 172 +202 237 +202 301 +202 243 +203 0 +203 9 +203 242 +203 53 +203 246 +203 377 +204 163 +204 5 +204 102 +204 267 +204 118 +204 55 +205 105 +205 60 +205 335 +205 337 +205 49 +205 252 +206 128 +206 78 +206 312 +206 25 +206 93 +206 223 +207 262 +207 235 +207 143 +207 304 +207 273 +207 381 +208 197 +208 140 +208 114 +208 374 +208 119 +208 255 +209 304 +209 370 +209 343 +209 58 +209 379 +209 28 +210 130 +210 69 +210 108 +210 376 +210 345 +210 28 +211 3 +211 17 +211 19 +211 150 +211 248 +211 382 +212 0 +212 1 +212 148 +212 214 +212 376 +212 57 +213 268 +213 141 +213 46 +213 271 +213 85 +213 158 +214 324 +214 137 +214 201 +214 179 +214 212 +214 342 +215 35 +215 356 +215 90 +215 106 +215 242 +215 314 +216 292 +216 71 +216 140 +216 307 +216 147 +216 31 +217 322 +217 359 +217 235 +217 88 +217 57 +217 250 +218 289 +218 132 +218 269 +218 85 +218 91 +218 287 +219 64 +219 257 +219 354 +219 113 +219 277 +219 286 +220 162 +220 70 +220 332 +220 145 +220 243 +220 29 +221 137 +221 146 +221 276 +221 117 +221 58 +221 31 +222 362 +222 239 +222 144 +222 124 +222 185 +222 60 +223 136 +223 331 +223 206 +223 367 +223 58 +223 348 +224 65 +224 265 +224 45 +224 77 +224 343 +224 124 +225 260 +225 136 +225 143 +225 276 +225 380 +225 31 +226 294 +226 331 +226 114 +226 243 +226 24 +226 345 +227 200 +227 273 +227 116 +227 55 +227 316 +227 125 +228 176 +228 148 +228 153 +228 348 +228 349 +228 254 +229 326 +229 296 +229 243 +229 276 +229 22 +229 344 +230 161 +230 71 +230 295 +230 361 +230 185 +230 159 +231 130 +231 70 +231 363 +231 79 +231 18 +231 179 +232 121 +232 237 +232 370 +232 83 +232 245 +232 57 +233 355 +233 305 +233 178 +233 308 +233 182 +233 120 +234 263 +234 360 +234 187 +234 114 +234 379 +234 28 +235 110 +235 207 +235 87 +235 312 +235 217 +235 351 +236 160 +236 194 +236 200 +236 78 +236 346 +236 315 +237 67 +237 292 +237 5 +237 232 +237 202 +237 238 +238 261 +238 133 +238 237 +238 80 +238 341 +238 348 +239 195 +239 328 +239 303 +239 176 +239 59 +239 222 +240 328 +240 143 +240 16 +240 177 +240 335 +240 50 +241 133 +241 103 +241 110 +241 177 +241 306 +241 120 +242 8 +242 136 +242 203 +242 215 +242 58 +242 255 +243 226 +243 229 +243 40 +243 136 +243 202 +243 220 +244 129 +244 323 +244 106 +244 362 +244 369 +244 374 +245 193 +245 232 +245 298 +245 11 +245 269 +245 17 +246 161 +246 75 +246 203 +246 251 +246 284 +246 383 +247 4 +247 167 +247 365 +247 368 +247 180 +247 123 +248 70 +248 13 +248 175 +248 211 +248 89 +248 318 +249 291 +249 383 +249 298 +249 339 +249 93 +249 95 +250 64 +250 338 +250 82 +250 189 +250 217 +250 381 +251 256 +251 164 +251 138 +251 307 +251 246 +251 281 +252 39 +252 328 +252 76 +252 205 +252 337 +252 372 +253 96 +253 132 +253 12 +253 76 +253 315 +253 63 +254 193 +254 164 +254 228 +254 36 +254 4 +254 140 +255 327 +255 366 +255 208 +255 242 +255 84 +255 27 +256 2 +256 263 +256 168 +256 51 +256 251 +256 382 +257 128 +257 357 +257 41 +257 275 +257 219 +257 284 +258 288 +258 36 +258 199 +258 362 +258 117 +258 59 +259 193 +259 134 +259 268 +259 364 +259 47 +259 347 +260 225 +260 354 +260 358 +260 266 +260 107 +260 110 +261 44 +261 238 +261 110 +261 144 +261 187 +261 60 +262 320 +262 292 +262 268 +262 207 +262 118 +262 186 +263 256 +263 291 +263 234 +263 371 +263 126 +263 95 +264 131 +264 38 +264 269 +264 152 +264 121 +264 186 +265 224 +265 356 +265 11 +265 48 +265 51 +265 276 +266 32 +266 260 +266 105 +266 138 +266 340 +266 56 +267 132 +267 204 +267 174 +267 368 +267 147 +267 29 +268 3 +268 259 +268 262 +268 39 +268 213 +268 88 +269 192 +269 264 +269 113 +269 148 +269 245 +269 218 +270 194 +270 323 +270 330 +270 301 +270 278 +270 186 +271 320 +271 1 +271 175 +271 180 +271 213 +271 60 +272 1 +272 139 +272 47 +272 303 +272 52 +272 375 +273 227 +273 26 +273 207 +273 340 +273 154 +273 379 +274 357 +274 70 +274 170 +274 364 +274 82 +274 151 +275 161 +275 257 +275 329 +275 368 +275 315 +275 95 +276 225 +276 35 +276 229 +276 265 +276 111 +276 221 +277 128 +277 40 +277 142 +277 79 +277 307 +277 219 +278 295 +278 75 +278 142 +278 270 +278 20 +278 181 +279 100 +279 81 +279 307 +279 150 +279 347 +279 124 +280 64 +280 294 +280 6 +280 200 +280 74 +280 330 +281 39 +281 366 +281 83 +281 61 +281 251 +281 29 +282 1 +282 66 +282 100 +282 79 +282 304 +282 287 +283 11 +283 149 +283 342 +283 54 +283 151 +283 190 +284 257 +284 357 +284 198 +284 368 +284 340 +284 246 +285 329 +285 108 +285 306 +285 179 +285 90 +285 63 +286 70 +286 14 +286 336 +286 89 +286 219 +286 191 +287 128 +287 71 +287 282 +287 378 +287 218 +287 127 +288 258 +288 195 +288 295 +288 7 +288 44 +288 89 +289 165 +289 154 +289 169 +289 364 +289 140 +289 218 +290 33 +290 80 +290 116 +290 149 +290 310 +290 23 +291 324 +291 263 +291 137 +291 249 +291 155 +291 350 +292 262 +292 237 +292 111 +292 176 +292 311 +292 216 +293 196 +293 135 +293 7 +293 297 +293 339 +293 28 +294 226 +294 169 +294 14 +294 47 +294 306 +294 280 +295 288 +295 230 +295 74 +295 278 +295 184 +295 94 +296 99 +296 229 +296 6 +296 333 +296 303 +296 191 +297 131 +297 293 +297 166 +297 13 +297 48 +297 149 +298 99 +298 196 +298 201 +298 245 +298 117 +298 249 +299 102 +299 202 +299 339 +299 371 +299 182 +299 311 +300 356 +300 325 +300 201 +300 301 +300 184 +300 123 +301 9 +301 202 +301 300 +301 142 +301 270 +301 350 +302 129 +302 101 +302 359 +302 200 +302 14 +302 47 +303 296 +303 43 +303 239 +303 272 +303 338 +303 153 +304 1 +304 207 +304 209 +304 282 +304 62 +304 127 +305 65 +305 38 +305 233 +305 18 +305 24 +305 155 +306 294 +306 241 +306 146 +306 371 +306 285 +306 93 +307 109 +307 115 +307 277 +307 279 +307 216 +307 251 +308 34 +308 233 +308 13 +308 366 +308 182 +308 61 +309 159 +309 360 +309 42 +309 15 +309 111 +309 63 +310 290 +310 7 +310 362 +310 332 +310 19 +310 346 +311 292 +311 107 +311 299 +311 86 +311 31 +311 351 +312 363 +312 235 +312 206 +312 155 +312 157 +312 30 +313 2 +313 98 +313 174 +313 116 +313 123 +313 318 +314 35 +314 114 +314 20 +314 150 +314 215 +314 25 +315 40 +315 236 +315 275 +315 52 +315 120 +315 253 +316 353 +316 129 +316 227 +316 321 +316 112 +316 57 +317 116 +317 372 +317 373 +317 344 +317 27 +317 381 +318 326 +318 359 +318 105 +318 248 +318 313 +318 126 +319 33 +319 37 +319 335 +319 16 +319 343 +319 346 +320 352 +320 134 +320 262 +320 173 +320 271 +320 28 +321 194 +321 72 +321 170 +321 75 +321 91 +321 316 +322 78 +322 145 +322 85 +322 23 +322 217 +322 93 +323 68 +323 42 +323 270 +323 338 +323 244 +323 191 +324 97 +324 291 +324 369 +324 18 +324 17 +324 214 +325 300 +325 108 +325 61 +325 181 +325 29 +325 158 +326 229 +326 71 +326 113 +326 150 +326 87 +326 318 +327 130 +327 101 +327 141 +327 341 +327 187 +327 255 +328 160 +328 132 +328 79 +328 240 +328 239 +328 252 +329 166 +329 369 +329 178 +329 275 +329 123 +329 285 +330 99 +330 71 +330 270 +330 373 +330 280 +330 93 +331 226 +331 134 +331 135 +331 169 +331 173 +331 223 +332 3 +332 4 +332 106 +332 172 +332 310 +332 220 +333 35 +333 296 +333 8 +333 360 +333 144 +333 124 +334 64 +334 133 +334 10 +334 144 +334 346 +334 62 +335 205 +335 240 +335 84 +335 182 +335 121 +335 319 +336 354 +336 36 +336 80 +336 347 +336 286 +336 191 +337 164 +337 37 +337 205 +337 83 +337 380 +337 252 +338 323 +338 364 +338 303 +338 145 +338 250 +338 382 +339 293 +339 299 +339 14 +339 114 +339 249 +339 92 +340 266 +340 273 +340 151 +340 26 +340 284 +340 125 +341 327 +341 11 +341 238 +341 20 +341 119 +341 349 +342 354 +342 171 +342 214 +342 120 +342 378 +342 283 +343 32 +343 224 +343 355 +343 80 +343 209 +343 319 +344 35 +344 67 +344 229 +344 82 +344 118 +344 317 +345 226 +345 66 +345 136 +345 139 +345 210 +345 155 +346 236 +346 334 +346 84 +346 310 +346 190 +346 319 +347 259 +347 6 +347 336 +347 85 +347 279 +347 184 +348 192 +348 228 +348 76 +348 238 +348 21 +348 223 +349 228 +349 104 +349 361 +349 372 +349 341 +349 185 +350 291 +350 70 +350 43 +350 301 +350 174 +350 152 +351 72 +351 235 +351 46 +351 143 +351 311 +351 125 +352 320 +352 100 +352 6 +352 39 +352 146 +352 190 +353 356 +353 38 +353 41 +353 141 +353 368 +353 316 +354 2 +354 163 +354 260 +354 336 +354 342 +354 219 +355 233 +355 109 +355 118 +355 343 +355 185 +355 155 +356 353 +356 165 +356 265 +356 300 +356 215 +356 95 +357 257 +357 274 +357 116 +357 378 +357 284 +357 191 +358 260 +358 170 +358 139 +358 14 +358 84 +358 125 +359 360 +359 302 +359 81 +359 376 +359 217 +359 318 +360 359 +360 234 +360 139 +360 333 +360 178 +360 309 +361 230 +361 15 +361 157 +361 374 +361 59 +361 349 +362 258 +362 370 +362 244 +362 310 +362 157 +362 222 +363 193 +363 231 +363 19 +363 312 +363 27 +363 61 +364 289 +364 259 +364 133 +364 111 +364 274 +364 338 +365 102 +365 200 +365 142 +365 53 +365 247 +365 31 +366 121 +366 34 +366 78 +366 308 +366 281 +366 255 +367 97 +367 134 +367 44 +367 184 +367 158 +367 223 +368 353 +368 267 +368 77 +368 275 +368 247 +368 284 +369 324 +369 40 +369 329 +369 144 +369 244 +369 119 +370 161 +370 163 +370 232 +370 362 +370 209 +370 148 +371 98 +371 39 +371 263 +371 299 +371 306 +371 56 +372 41 +372 44 +372 252 +372 125 +372 349 +372 317 +373 330 +373 45 +373 144 +373 375 +373 317 +373 382 +374 5 +374 361 +374 208 +374 244 +374 151 +374 191 +375 132 +375 134 +375 272 +375 177 +375 148 +375 373 +376 5 +376 359 +376 199 +376 75 +376 210 +376 212 +377 73 +377 107 +377 203 +377 173 +377 78 +377 62 +378 357 +378 104 +378 201 +378 342 +378 57 +378 287 +379 68 +379 6 +379 234 +379 209 +379 273 +379 26 +380 225 +380 102 +380 38 +380 15 +380 337 +380 159 +381 32 +381 122 +381 207 +381 250 +381 92 +381 317 +382 256 +382 46 +382 338 +382 83 +382 211 +382 373 +383 135 +383 109 +383 246 +383 24 +383 249 +383 156 diff --git a/random files/96_star.edges b/random files/96_star.edges new file mode 100644 index 0000000000000000000000000000000000000000..c13fb7be4ce14750d76a8b636a6a666f548e19f6 --- /dev/null +++ b/random files/96_star.edges @@ -0,0 +1,191 @@ +96 +0 1 +0 2 +0 3 +0 4 +0 5 +0 6 +0 7 +0 8 +0 9 +0 10 +0 11 +0 12 +0 13 +0 14 +0 15 +0 16 +0 17 +0 18 +0 19 +0 20 +0 21 +0 22 +0 23 +0 24 +0 25 +0 26 +0 27 +0 28 +0 29 +0 30 +0 31 +0 32 +0 33 +0 34 +0 35 +0 36 +0 37 +0 38 +0 39 +0 40 +0 41 +0 42 +0 43 +0 44 +0 45 +0 46 +0 47 +0 48 +0 49 +0 50 +0 51 +0 52 +0 53 +0 54 +0 55 +0 56 +0 57 +0 58 +0 59 +0 60 +0 61 +0 62 +0 63 +0 64 +0 65 +0 66 +0 67 +0 68 +0 69 +0 70 +0 71 +0 72 +0 73 +0 74 +0 75 +0 76 +0 77 +0 78 +0 79 +0 80 +0 81 +0 82 +0 83 +0 84 +0 85 +0 86 +0 87 +0 88 +0 89 +0 90 +0 91 +0 92 +0 93 +0 94 +0 95 +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +10 0 +11 0 +12 0 +13 0 +14 0 +15 0 +16 0 +17 0 +18 0 +19 0 +20 0 +21 0 +22 0 +23 0 +24 0 +25 0 +26 0 +27 0 +28 0 +29 0 +30 0 +31 0 +32 0 +33 0 +34 0 +35 0 +36 0 +37 0 +38 0 +39 0 +40 0 +41 0 +42 0 +43 0 +44 0 +45 0 +46 0 +47 0 +48 0 +49 0 +50 0 +51 0 +52 0 +53 0 +54 0 +55 0 +56 0 +57 0 +58 0 +59 0 +60 0 +61 0 +62 0 +63 0 +64 0 +65 0 +66 0 +67 0 +68 0 +69 0 +70 0 +71 0 +72 0 +73 0 +74 0 +75 0 +76 0 +77 0 +78 0 +79 0 +80 0 +81 0 +82 0 +83 0 +84 0 +85 0 +86 0 +87 0 +88 0 +89 0 +90 0 +91 0 +92 0 +93 0 +94 0 +95 0 diff --git a/random files/96_star.png b/random files/96_star.png new file mode 100644 index 0000000000000000000000000000000000000000..09920814dabde2b899fcbe1ab977939ca795db38 Binary files /dev/null and b/random files/96_star.png differ diff --git a/random files/Diff0:1000.png b/random files/Diff0:1000.png new file mode 100644 index 0000000000000000000000000000000000000000..b89db60f820b75abeb52eb7692bb84c345d95b8a Binary files /dev/null and b/random files/Diff0:1000.png differ diff --git a/random files/FFT_Histogram.png b/random files/FFT_Histogram.png new file mode 100644 index 0000000000000000000000000000000000000000..87df077759c3759f0a8264d7ceda7ad688dddf41 Binary files /dev/null and b/random files/FFT_Histogram.png differ diff --git a/random files/Freq_Diff_Values.png b/random files/Freq_Diff_Values.png new file mode 100644 index 0000000000000000000000000000000000000000..0019df17b23b220780edddd4fd9a693cc1934284 Binary files /dev/null and b/random files/Freq_Diff_Values.png differ diff --git a/random files/Freq_Values.png b/random files/Freq_Values.png new file mode 100644 index 0000000000000000000000000000000000000000..0530030d053b6f04262a90115ecb68303d9cf36f Binary files /dev/null and b/random files/Freq_Values.png differ diff --git a/random files/Gradient_Values.png b/random files/Gradient_Values.png new file mode 100644 index 0000000000000000000000000000000000000000..a16236956d202b260d4dccb3ec53d761a8072d0f Binary files /dev/null and b/random files/Gradient_Values.png differ diff --git a/random files/Hist.png b/random files/Hist.png new file mode 100644 index 0000000000000000000000000000000000000000..80505aed9b005f27275711e8fdc1db29bdf8e287 Binary files /dev/null and b/random files/Hist.png differ diff --git a/random files/Parameter_Frequency.png b/random files/Parameter_Frequency.png new file mode 100644 index 0000000000000000000000000000000000000000..d32539788254089c650aa9666fcc4888d2186c27 Binary files /dev/null and b/random files/Parameter_Frequency.png differ diff --git a/random files/Parameter_Histogram.png b/random files/Parameter_Histogram.png new file mode 100644 index 0000000000000000000000000000000000000000..1a8e0944b86812ba245c508434b8bf47e5a9a2e0 Binary files /dev/null and b/random files/Parameter_Histogram.png differ diff --git a/random files/Parameter_Values.png b/random files/Parameter_Values.png new file mode 100644 index 0000000000000000000000000000000000000000..395ff86c53ab932e2d508d214f5d4ebe8ffdbcef Binary files /dev/null and b/random files/Parameter_Values.png differ diff --git a/random files/Parameters.png b/random files/Parameters.png new file mode 100644 index 0000000000000000000000000000000000000000..6e062d0496d180109da09ff68cee1bc248010e69 Binary files /dev/null and b/random files/Parameters.png differ diff --git a/random files/ParametersWaveletHaar.png b/random files/ParametersWaveletHaar.png new file mode 100644 index 0000000000000000000000000000000000000000..b89db60f820b75abeb52eb7692bb84c345d95b8a Binary files /dev/null and b/random files/ParametersWaveletHaar.png differ diff --git a/random files/ParametersWaveletHaar.svg b/random files/ParametersWaveletHaar.svg new file mode 100644 index 0000000000000000000000000000000000000000..f65da72e8eafd16892bad85a57bcf03b5ea92b86 --- /dev/null +++ b/random files/ParametersWaveletHaar.svg @@ -0,0 +1,2332 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="432pt" height="288pt" viewBox="0 0 432 288" xmlns="http://www.w3.org/2000/svg" version="1.1"> + <metadata> + <rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> + <cc:Work> + <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> + <dc:date>2022-03-23T20:37:51.057299</dc:date> + <dc:format>image/svg+xml</dc:format> + <dc:creator> + <cc:Agent> + <dc:title>Matplotlib v3.5.1, https://matplotlib.org/</dc:title> + </cc:Agent> + </dc:creator> + </cc:Work> + </rdf:RDF> + </metadata> + <defs> + <style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style> + </defs> + <g id="figure_1"> + <g id="patch_1"> + <path d="M 0 288 +L 432 288 +L 432 0 +L 0 0 +L 0 288 +z +" style="fill: none"/> + </g> + <g id="axes_1"> + <g id="patch_2"> + <path d="M 54 252 +L 388.8 252 +L 388.8 34.56 +L 54 34.56 +z +" style="fill: #ffffff"/> + </g> + <g id="matplotlib.axis_1"> + <g id="xtick_1"> + <g id="line2d_1"> + <defs> + <path id="m20d77cf94f" d="M 0 0 +L 0 3.5 +" style="stroke: #000000; stroke-width: 0.8"/> + </defs> + <g> + <use xlink:href="#m20d77cf94f" x="69.218182" y="252" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_1"> + <!-- 40000 --> + <g transform="translate(53.311932 266.598437)scale(0.1 -0.1)"> + <defs> + <path id="DejaVuSans-34" d="M 2419 4116 +L 825 1625 +L 2419 1625 +L 2419 4116 +z +M 2253 4666 +L 3047 4666 +L 3047 1625 +L 3713 1625 +L 3713 1100 +L 3047 1100 +L 3047 0 +L 2419 0 +L 2419 1100 +L 313 1100 +L 313 1709 +L 2253 4666 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-30" d="M 2034 4250 +Q 1547 4250 1301 3770 +Q 1056 3291 1056 2328 +Q 1056 1369 1301 889 +Q 1547 409 2034 409 +Q 2525 409 2770 889 +Q 3016 1369 3016 2328 +Q 3016 3291 2770 3770 +Q 2525 4250 2034 4250 +z +M 2034 4750 +Q 2819 4750 3233 4129 +Q 3647 3509 3647 2328 +Q 3647 1150 3233 529 +Q 2819 -91 2034 -91 +Q 1250 -91 836 529 +Q 422 1150 422 2328 +Q 422 3509 836 4129 +Q 1250 4750 2034 4750 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-34"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-30" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + <use xlink:href="#DejaVuSans-30" x="254.492188"/> + </g> + </g> + </g> + <g id="xtick_2"> + <g id="line2d_2"> + <g> + <use xlink:href="#m20d77cf94f" x="130.151843" y="252" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_2"> + <!-- 40200 --> + <g transform="translate(114.245593 266.598437)scale(0.1 -0.1)"> + <defs> + <path id="DejaVuSans-32" d="M 1228 531 +L 3431 531 +L 3431 0 +L 469 0 +L 469 531 +Q 828 903 1448 1529 +Q 2069 2156 2228 2338 +Q 2531 2678 2651 2914 +Q 2772 3150 2772 3378 +Q 2772 3750 2511 3984 +Q 2250 4219 1831 4219 +Q 1534 4219 1204 4116 +Q 875 4013 500 3803 +L 500 4441 +Q 881 4594 1212 4672 +Q 1544 4750 1819 4750 +Q 2544 4750 2975 4387 +Q 3406 4025 3406 3419 +Q 3406 3131 3298 2873 +Q 3191 2616 2906 2266 +Q 2828 2175 2409 1742 +Q 1991 1309 1228 531 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-34"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-32" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + <use xlink:href="#DejaVuSans-30" x="254.492188"/> + </g> + </g> + </g> + <g id="xtick_3"> + <g id="line2d_3"> + <g> + <use xlink:href="#m20d77cf94f" x="191.085504" y="252" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_3"> + <!-- 40400 --> + <g transform="translate(175.179254 266.598437)scale(0.1 -0.1)"> + <use xlink:href="#DejaVuSans-34"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-34" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + <use xlink:href="#DejaVuSans-30" x="254.492188"/> + </g> + </g> + </g> + <g id="xtick_4"> + <g id="line2d_4"> + <g> + <use xlink:href="#m20d77cf94f" x="252.019165" y="252" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_4"> + <!-- 40600 --> + <g transform="translate(236.112915 266.598437)scale(0.1 -0.1)"> + <defs> + <path id="DejaVuSans-36" d="M 2113 2584 +Q 1688 2584 1439 2293 +Q 1191 2003 1191 1497 +Q 1191 994 1439 701 +Q 1688 409 2113 409 +Q 2538 409 2786 701 +Q 3034 994 3034 1497 +Q 3034 2003 2786 2293 +Q 2538 2584 2113 2584 +z +M 3366 4563 +L 3366 3988 +Q 3128 4100 2886 4159 +Q 2644 4219 2406 4219 +Q 1781 4219 1451 3797 +Q 1122 3375 1075 2522 +Q 1259 2794 1537 2939 +Q 1816 3084 2150 3084 +Q 2853 3084 3261 2657 +Q 3669 2231 3669 1497 +Q 3669 778 3244 343 +Q 2819 -91 2113 -91 +Q 1303 -91 875 529 +Q 447 1150 447 2328 +Q 447 3434 972 4092 +Q 1497 4750 2381 4750 +Q 2619 4750 2861 4703 +Q 3103 4656 3366 4563 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-34"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-36" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + <use xlink:href="#DejaVuSans-30" x="254.492188"/> + </g> + </g> + </g> + <g id="xtick_5"> + <g id="line2d_5"> + <g> + <use xlink:href="#m20d77cf94f" x="312.952826" y="252" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_5"> + <!-- 40800 --> + <g transform="translate(297.046576 266.598437)scale(0.1 -0.1)"> + <defs> + <path id="DejaVuSans-38" d="M 2034 2216 +Q 1584 2216 1326 1975 +Q 1069 1734 1069 1313 +Q 1069 891 1326 650 +Q 1584 409 2034 409 +Q 2484 409 2743 651 +Q 3003 894 3003 1313 +Q 3003 1734 2745 1975 +Q 2488 2216 2034 2216 +z +M 1403 2484 +Q 997 2584 770 2862 +Q 544 3141 544 3541 +Q 544 4100 942 4425 +Q 1341 4750 2034 4750 +Q 2731 4750 3128 4425 +Q 3525 4100 3525 3541 +Q 3525 3141 3298 2862 +Q 3072 2584 2669 2484 +Q 3125 2378 3379 2068 +Q 3634 1759 3634 1313 +Q 3634 634 3220 271 +Q 2806 -91 2034 -91 +Q 1263 -91 848 271 +Q 434 634 434 1313 +Q 434 1759 690 2068 +Q 947 2378 1403 2484 +z +M 1172 3481 +Q 1172 3119 1398 2916 +Q 1625 2713 2034 2713 +Q 2441 2713 2670 2916 +Q 2900 3119 2900 3481 +Q 2900 3844 2670 4047 +Q 2441 4250 2034 4250 +Q 1625 4250 1398 4047 +Q 1172 3844 1172 3481 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-34"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-38" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + <use xlink:href="#DejaVuSans-30" x="254.492188"/> + </g> + </g> + </g> + <g id="xtick_6"> + <g id="line2d_6"> + <g> + <use xlink:href="#m20d77cf94f" x="373.886486" y="252" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_6"> + <!-- 41000 --> + <g transform="translate(357.980236 266.598437)scale(0.1 -0.1)"> + <defs> + <path id="DejaVuSans-31" d="M 794 531 +L 1825 531 +L 1825 4091 +L 703 3866 +L 703 4441 +L 1819 4666 +L 2450 4666 +L 2450 531 +L 3481 531 +L 3481 0 +L 794 0 +L 794 531 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-34"/> + <use xlink:href="#DejaVuSans-31" x="63.623047"/> + <use xlink:href="#DejaVuSans-30" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + <use xlink:href="#DejaVuSans-30" x="254.492188"/> + </g> + </g> + </g> + <g id="text_7"> + <!-- Parameter indices --> + <g transform="translate(176.246875 280.276563)scale(0.1 -0.1)"> + <defs> + <path id="DejaVuSans-50" d="M 1259 4147 +L 1259 2394 +L 2053 2394 +Q 2494 2394 2734 2622 +Q 2975 2850 2975 3272 +Q 2975 3691 2734 3919 +Q 2494 4147 2053 4147 +L 1259 4147 +z +M 628 4666 +L 2053 4666 +Q 2838 4666 3239 4311 +Q 3641 3956 3641 3272 +Q 3641 2581 3239 2228 +Q 2838 1875 2053 1875 +L 1259 1875 +L 1259 0 +L 628 0 +L 628 4666 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-61" d="M 2194 1759 +Q 1497 1759 1228 1600 +Q 959 1441 959 1056 +Q 959 750 1161 570 +Q 1363 391 1709 391 +Q 2188 391 2477 730 +Q 2766 1069 2766 1631 +L 2766 1759 +L 2194 1759 +z +M 3341 1997 +L 3341 0 +L 2766 0 +L 2766 531 +Q 2569 213 2275 61 +Q 1981 -91 1556 -91 +Q 1019 -91 701 211 +Q 384 513 384 1019 +Q 384 1609 779 1909 +Q 1175 2209 1959 2209 +L 2766 2209 +L 2766 2266 +Q 2766 2663 2505 2880 +Q 2244 3097 1772 3097 +Q 1472 3097 1187 3025 +Q 903 2953 641 2809 +L 641 3341 +Q 956 3463 1253 3523 +Q 1550 3584 1831 3584 +Q 2591 3584 2966 3190 +Q 3341 2797 3341 1997 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-72" d="M 2631 2963 +Q 2534 3019 2420 3045 +Q 2306 3072 2169 3072 +Q 1681 3072 1420 2755 +Q 1159 2438 1159 1844 +L 1159 0 +L 581 0 +L 581 3500 +L 1159 3500 +L 1159 2956 +Q 1341 3275 1631 3429 +Q 1922 3584 2338 3584 +Q 2397 3584 2469 3576 +Q 2541 3569 2628 3553 +L 2631 2963 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-6d" d="M 3328 2828 +Q 3544 3216 3844 3400 +Q 4144 3584 4550 3584 +Q 5097 3584 5394 3201 +Q 5691 2819 5691 2113 +L 5691 0 +L 5113 0 +L 5113 2094 +Q 5113 2597 4934 2840 +Q 4756 3084 4391 3084 +Q 3944 3084 3684 2787 +Q 3425 2491 3425 1978 +L 3425 0 +L 2847 0 +L 2847 2094 +Q 2847 2600 2669 2842 +Q 2491 3084 2119 3084 +Q 1678 3084 1418 2786 +Q 1159 2488 1159 1978 +L 1159 0 +L 581 0 +L 581 3500 +L 1159 3500 +L 1159 2956 +Q 1356 3278 1631 3431 +Q 1906 3584 2284 3584 +Q 2666 3584 2933 3390 +Q 3200 3197 3328 2828 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-65" d="M 3597 1894 +L 3597 1613 +L 953 1613 +Q 991 1019 1311 708 +Q 1631 397 2203 397 +Q 2534 397 2845 478 +Q 3156 559 3463 722 +L 3463 178 +Q 3153 47 2828 -22 +Q 2503 -91 2169 -91 +Q 1331 -91 842 396 +Q 353 884 353 1716 +Q 353 2575 817 3079 +Q 1281 3584 2069 3584 +Q 2775 3584 3186 3129 +Q 3597 2675 3597 1894 +z +M 3022 2063 +Q 3016 2534 2758 2815 +Q 2500 3097 2075 3097 +Q 1594 3097 1305 2825 +Q 1016 2553 972 2059 +L 3022 2063 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-74" d="M 1172 4494 +L 1172 3500 +L 2356 3500 +L 2356 3053 +L 1172 3053 +L 1172 1153 +Q 1172 725 1289 603 +Q 1406 481 1766 481 +L 2356 481 +L 2356 0 +L 1766 0 +Q 1100 0 847 248 +Q 594 497 594 1153 +L 594 3053 +L 172 3053 +L 172 3500 +L 594 3500 +L 594 4494 +L 1172 4494 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-20" transform="scale(0.015625)"/> + <path id="DejaVuSans-69" d="M 603 3500 +L 1178 3500 +L 1178 0 +L 603 0 +L 603 3500 +z +M 603 4863 +L 1178 4863 +L 1178 4134 +L 603 4134 +L 603 4863 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-6e" d="M 3513 2113 +L 3513 0 +L 2938 0 +L 2938 2094 +Q 2938 2591 2744 2837 +Q 2550 3084 2163 3084 +Q 1697 3084 1428 2787 +Q 1159 2491 1159 1978 +L 1159 0 +L 581 0 +L 581 3500 +L 1159 3500 +L 1159 2956 +Q 1366 3272 1645 3428 +Q 1925 3584 2291 3584 +Q 2894 3584 3203 3211 +Q 3513 2838 3513 2113 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-64" d="M 2906 2969 +L 2906 4863 +L 3481 4863 +L 3481 0 +L 2906 0 +L 2906 525 +Q 2725 213 2448 61 +Q 2172 -91 1784 -91 +Q 1150 -91 751 415 +Q 353 922 353 1747 +Q 353 2572 751 3078 +Q 1150 3584 1784 3584 +Q 2172 3584 2448 3432 +Q 2725 3281 2906 2969 +z +M 947 1747 +Q 947 1113 1208 752 +Q 1469 391 1925 391 +Q 2381 391 2643 752 +Q 2906 1113 2906 1747 +Q 2906 2381 2643 2742 +Q 2381 3103 1925 3103 +Q 1469 3103 1208 2742 +Q 947 2381 947 1747 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-63" d="M 3122 3366 +L 3122 2828 +Q 2878 2963 2633 3030 +Q 2388 3097 2138 3097 +Q 1578 3097 1268 2742 +Q 959 2388 959 1747 +Q 959 1106 1268 751 +Q 1578 397 2138 397 +Q 2388 397 2633 464 +Q 2878 531 3122 666 +L 3122 134 +Q 2881 22 2623 -34 +Q 2366 -91 2075 -91 +Q 1284 -91 818 406 +Q 353 903 353 1747 +Q 353 2603 823 3093 +Q 1294 3584 2113 3584 +Q 2378 3584 2631 3529 +Q 2884 3475 3122 3366 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-73" d="M 2834 3397 +L 2834 2853 +Q 2591 2978 2328 3040 +Q 2066 3103 1784 3103 +Q 1356 3103 1142 2972 +Q 928 2841 928 2578 +Q 928 2378 1081 2264 +Q 1234 2150 1697 2047 +L 1894 2003 +Q 2506 1872 2764 1633 +Q 3022 1394 3022 966 +Q 3022 478 2636 193 +Q 2250 -91 1575 -91 +Q 1294 -91 989 -36 +Q 684 19 347 128 +L 347 722 +Q 666 556 975 473 +Q 1284 391 1588 391 +Q 1994 391 2212 530 +Q 2431 669 2431 922 +Q 2431 1156 2273 1281 +Q 2116 1406 1581 1522 +L 1381 1569 +Q 847 1681 609 1914 +Q 372 2147 372 2553 +Q 372 3047 722 3315 +Q 1072 3584 1716 3584 +Q 2034 3584 2315 3537 +Q 2597 3491 2834 3397 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-50"/> + <use xlink:href="#DejaVuSans-61" x="55.802734"/> + <use xlink:href="#DejaVuSans-72" x="117.082031"/> + <use xlink:href="#DejaVuSans-61" x="158.195312"/> + <use xlink:href="#DejaVuSans-6d" x="219.474609"/> + <use xlink:href="#DejaVuSans-65" x="316.886719"/> + <use xlink:href="#DejaVuSans-74" x="378.410156"/> + <use xlink:href="#DejaVuSans-65" x="417.619141"/> + <use xlink:href="#DejaVuSans-72" x="479.142578"/> + <use xlink:href="#DejaVuSans-20" x="520.255859"/> + <use xlink:href="#DejaVuSans-69" x="552.042969"/> + <use xlink:href="#DejaVuSans-6e" x="579.826172"/> + <use xlink:href="#DejaVuSans-64" x="643.205078"/> + <use xlink:href="#DejaVuSans-69" x="706.681641"/> + <use xlink:href="#DejaVuSans-63" x="734.464844"/> + <use xlink:href="#DejaVuSans-65" x="789.445312"/> + <use xlink:href="#DejaVuSans-73" x="850.96875"/> + </g> + </g> + </g> + <g id="matplotlib.axis_2"> + <g id="ytick_1"> + <g id="line2d_7"> + <defs> + <path id="mcae92e3e51" d="M 0 0 +L -3.5 0 +" style="stroke: #000000; stroke-width: 0.8"/> + </defs> + <g> + <use xlink:href="#mcae92e3e51" x="54" y="242.910438" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_8"> + <!-- 0 --> + <g transform="translate(40.6375 246.709657)scale(0.1 -0.1)"> + <use xlink:href="#DejaVuSans-30"/> + </g> + </g> + </g> + <g id="ytick_2"> + <g id="line2d_8"> + <g> + <use xlink:href="#mcae92e3e51" x="54" y="208.385466" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_9"> + <!-- 2000 --> + <g transform="translate(21.55 212.184685)scale(0.1 -0.1)"> + <use xlink:href="#DejaVuSans-32"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-30" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + </g> + </g> + </g> + <g id="ytick_3"> + <g id="line2d_9"> + <g> + <use xlink:href="#mcae92e3e51" x="54" y="173.860494" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_10"> + <!-- 4000 --> + <g transform="translate(21.55 177.659713)scale(0.1 -0.1)"> + <use xlink:href="#DejaVuSans-34"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-30" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + </g> + </g> + </g> + <g id="ytick_4"> + <g id="line2d_10"> + <g> + <use xlink:href="#mcae92e3e51" x="54" y="139.335522" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_11"> + <!-- 6000 --> + <g transform="translate(21.55 143.134741)scale(0.1 -0.1)"> + <use xlink:href="#DejaVuSans-36"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-30" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + </g> + </g> + </g> + <g id="ytick_5"> + <g id="line2d_11"> + <g> + <use xlink:href="#mcae92e3e51" x="54" y="104.81055" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_12"> + <!-- 8000 --> + <g transform="translate(21.55 108.609769)scale(0.1 -0.1)"> + <use xlink:href="#DejaVuSans-38"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-30" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + </g> + </g> + </g> + <g id="ytick_6"> + <g id="line2d_12"> + <g> + <use xlink:href="#mcae92e3e51" x="54" y="70.285578" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_13"> + <!-- 10000 --> + <g transform="translate(15.1875 74.084797)scale(0.1 -0.1)"> + <use xlink:href="#DejaVuSans-31"/> + <use xlink:href="#DejaVuSans-30" x="63.623047"/> + <use xlink:href="#DejaVuSans-30" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + <use xlink:href="#DejaVuSans-30" x="254.492188"/> + </g> + </g> + </g> + <g id="ytick_7"> + <g id="line2d_13"> + <g> + <use xlink:href="#mcae92e3e51" x="54" y="35.760606" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_14"> + <!-- 12000 --> + <g transform="translate(15.1875 39.559825)scale(0.1 -0.1)"> + <use xlink:href="#DejaVuSans-31"/> + <use xlink:href="#DejaVuSans-32" x="63.623047"/> + <use xlink:href="#DejaVuSans-30" x="127.246094"/> + <use xlink:href="#DejaVuSans-30" x="190.869141"/> + <use xlink:href="#DejaVuSans-30" x="254.492188"/> + </g> + </g> + </g> + </g> + <g id="line2d_14"> + <path d="M 69.218182 241.719326 +L 69.827518 241.788376 +L 70.132187 241.719326 +L 71.046192 241.805639 +L 71.35086 241.408602 +L 71.655528 241.477652 +L 71.960197 241.788376 +L 72.569533 241.702064 +L 72.874201 241.391339 +L 73.17887 241.374077 +L 73.483538 241.719326 +L 74.397543 241.736589 +L 75.00688 241.512177 +L 75.920885 241.719326 +L 76.225553 241.546702 +L 77.444226 241.719326 +L 77.748894 241.529439 +L 78.358231 241.563964 +L 78.662899 241.581227 +L 79.272236 241.218714 +L 79.881572 241.391339 +L 80.186241 241.339552 +L 80.490909 241.667539 +L 80.795577 241.598489 +L 81.404914 241.650277 +L 81.709582 241.667539 +L 82.014251 241.995526 +L 82.318919 241.943739 +L 82.928256 241.995526 +L 83.232924 240.76989 +L 83.537592 242.030051 +L 84.146929 241.926476 +L 84.451597 241.719326 +L 84.756265 241.028827 +L 85.060934 242.012789 +L 85.365602 241.270502 +L 85.67027 241.477652 +L 85.974939 240.70084 +L 86.279607 241.166927 +L 86.584275 241.391339 +L 87.193612 241.374077 +L 87.49828 241.305027 +L 87.802948 241.425864 +L 88.107617 241.736589 +L 88.716953 241.736589 +L 89.021622 241.719326 +L 89.32629 240.528215 +L 89.630958 241.961001 +L 90.240295 241.719326 +L 90.544963 241.04609 +L 90.849631 240.683577 +L 91.1543 241.822901 +L 91.458968 241.961001 +L 91.763636 241.028827 +L 92.068305 241.115139 +L 92.372973 240.735365 +L 92.677641 241.857426 +L 92.98231 241.961001 +L 93.591646 240.476427 +L 93.896314 240.718102 +L 94.200983 242.047314 +L 96.638329 241.995526 +L 96.942998 241.080614 +L 97.247666 241.667539 +L 97.552334 241.460389 +L 97.857002 241.477652 +L 98.161671 240.56274 +L 98.466339 240.666315 +L 98.771007 242.047314 +L 99.075676 241.529439 +L 99.380344 240.528215 +L 99.989681 240.56274 +L 100.294349 242.099101 +L 100.903686 240.49369 +L 101.208354 240.787152 +L 101.513022 240.580002 +L 101.81769 241.218714 +L 102.122359 241.115139 +L 102.427027 241.253239 +L 103.036364 241.184189 +L 103.341032 241.529439 +L 104.559705 241.529439 +L 104.864373 241.04609 +L 105.169042 240.856202 +L 105.778378 240.90799 +L 106.083047 240.718102 +L 106.387715 241.563964 +L 106.997052 241.512177 +L 107.606388 241.063352 +L 107.911057 241.529439 +L 108.215725 241.149664 +L 108.520393 241.305027 +L 108.825061 241.201452 +L 109.12973 241.305027 +L 109.434398 240.890727 +L 109.739066 241.028827 +L 110.348403 240.994302 +L 110.653071 240.890727 +L 110.95774 241.166927 +L 111.262408 241.253239 +L 111.871744 241.149664 +L 112.176413 241.166927 +L 112.481081 241.529439 +L 112.785749 241.408602 +L 113.090418 241.494914 +L 113.395086 241.443127 +L 113.699754 241.563964 +L 114.004423 241.460389 +L 114.309091 241.512177 +L 114.613759 241.149664 +L 115.223096 241.253239 +L 115.527764 241.494914 +L 116.137101 240.597265 +L 116.441769 240.597265 +L 116.746437 240.390115 +L 117.051106 241.339552 +L 117.965111 241.235977 +L 118.269779 241.391339 +L 118.574447 241.874689 +L 118.879115 241.961001 +L 119.183784 241.891951 +L 119.488452 242.030051 +L 119.79312 240.683577 +L 120.097789 241.477652 +L 120.707125 241.581227 +L 121.316462 240.21749 +L 121.62113 242.099101 +L 121.925799 242.099101 +L 122.230467 240.873465 +L 122.535135 240.70084 +L 122.839803 240.942515 +L 123.144472 241.943739 +L 123.44914 241.667539 +L 123.753808 240.90799 +L 124.058477 240.614527 +L 124.363145 240.56274 +L 124.667813 241.080614 +L 125.27715 240.90799 +L 125.886486 240.90799 +L 126.191155 241.253239 +L 126.800491 241.287764 +L 127.10516 240.942515 +L 127.409828 240.234753 +L 127.714496 241.494914 +L 128.323833 240.821677 +L 128.628501 240.63179 +L 128.93317 241.115139 +L 129.542506 240.890727 +L 129.847174 240.390115 +L 130.151843 240.597265 +L 130.456511 240.597265 +L 130.761179 240.856202 +L 131.370516 240.131178 +L 131.675184 240.787152 +L 131.979853 240.76989 +L 132.284521 240.165703 +L 132.589189 240.269278 +L 132.893857 240.165703 +L 134.112531 240.303803 +L 134.417199 240.165703 +L 134.721867 240.390115 +L 135.026536 240.14844 +L 135.331204 240.321065 +L 135.940541 240.35559 +L 136.549877 240.42464 +L 136.854545 240.649052 +L 137.463882 240.545477 +L 137.76855 241.063352 +L 138.073219 240.83894 +L 138.377887 240.441902 +L 138.987224 240.735365 +L 139.291892 240.752627 +L 139.901229 241.115139 +L 140.815233 241.04609 +L 141.119902 240.925252 +L 141.42457 241.080614 +L 142.338575 241.028827 +L 142.643243 240.49369 +L 142.947912 240.994302 +L 143.557248 240.994302 +L 143.861916 240.459165 +L 144.166585 240.28654 +L 144.471253 241.356814 +L 144.775921 240.70084 +L 145.385258 240.21749 +L 145.689926 240.76989 +L 145.994595 240.76989 +L 146.299263 240.649052 +L 146.603931 240.252015 +L 146.9086 240.407378 +L 147.213268 240.131178 +L 147.517936 241.132402 +L 148.127273 241.080614 +L 148.736609 241.115139 +L 149.041278 241.684801 +L 151.173956 241.374077 +L 151.478624 240.890727 +L 151.783292 240.890727 +L 152.087961 241.788376 +L 152.392629 241.753851 +L 152.697297 241.494914 +L 153.001966 240.303803 +L 153.306634 240.338328 +L 153.611302 241.667539 +L 153.915971 240.752627 +L 154.220639 240.372853 +L 154.525307 240.994302 +L 154.829975 240.942515 +L 155.134644 241.322289 +L 157.267322 241.287764 +L 157.57199 240.994302 +L 157.876658 241.028827 +L 158.181327 241.633014 +L 158.485995 241.598489 +L 159.095332 240.959777 +L 159.4 241.650277 +L 160.009337 241.460389 +L 160.314005 240.735365 +L 160.923342 240.666315 +L 161.22801 241.132402 +L 161.532678 240.441902 +L 162.446683 240.390115 +L 162.751351 241.011565 +L 163.970025 240.97704 +L 164.884029 240.994302 +L 165.188698 240.83894 +L 165.493366 240.942515 +L 165.798034 241.339552 +L 166.712039 241.287764 +L 167.016708 241.581227 +L 167.626044 241.080614 +L 167.930713 241.356814 +L 168.235381 241.356814 +L 168.844717 241.218714 +L 169.149386 241.270502 +L 169.454054 241.080614 +L 170.063391 240.97704 +L 170.368059 241.615752 +L 172.805405 241.650277 +L 174.024079 241.408602 +L 174.633415 240.372853 +L 174.938084 241.874689 +L 175.54742 241.201452 +L 175.852088 240.131178 +L 176.156757 240.321065 +L 176.461425 241.253239 +L 177.070762 240.407378 +L 177.680098 240.407378 +L 177.984767 240.90799 +L 178.594103 240.856202 +L 178.898771 240.580002 +L 179.20344 240.925252 +L 179.508108 240.925252 +L 179.812776 241.04609 +L 180.422113 240.959777 +L 180.726781 241.253239 +L 181.640786 240.97704 +L 181.945455 240.718102 +L 182.250123 240.735365 +L 182.554791 241.305027 +L 182.859459 241.235977 +L 183.468796 240.459165 +L 183.773464 241.218714 +L 184.078133 241.235977 +L 184.687469 240.252015 +L 185.296806 240.890727 +L 185.601474 240.528215 +L 187.124816 240.597265 +L 187.734152 240.63179 +L 188.038821 240.510952 +L 188.648157 240.76989 +L 188.952826 240.735365 +L 189.257494 240.873465 +L 189.562162 240.649052 +L 189.86683 239.87224 +L 190.171499 240.804415 +L 190.476167 240.942515 +L 190.780835 240.83894 +L 191.390172 240.269278 +L 191.69484 240.890727 +L 191.999509 240.873465 +L 192.304177 240.321065 +L 192.608845 240.234753 +L 192.913514 240.269278 +L 193.218182 241.149664 +L 193.52285 240.959777 +L 193.827518 241.04609 +L 194.132187 240.90799 +L 194.436855 240.942515 +L 194.741523 241.201452 +L 195.655528 241.149664 +L 195.960197 240.787152 +L 196.874201 240.90799 +L 197.17887 240.666315 +L 197.483538 240.027603 +L 197.788206 241.305027 +L 198.092875 241.115139 +L 198.702211 240.476427 +L 199.00688 240.49369 +L 199.311548 241.063352 +L 199.616216 241.080614 +L 199.920885 241.581227 +L 200.225553 240.372853 +L 200.530221 240.269278 +L 200.834889 240.959777 +L 201.139558 241.080614 +L 201.748894 241.063352 +L 202.053563 241.115139 +L 202.358231 240.83894 +L 202.662899 241.132402 +L 202.967568 240.76989 +L 203.272236 241.080614 +L 203.576904 241.011565 +L 203.881572 241.097877 +L 204.490909 240.821677 +L 204.795577 240.269278 +L 205.100246 240.14844 +L 205.404914 241.425864 +L 205.709582 241.374077 +L 206.014251 240.476427 +L 206.623587 240.787152 +L 206.928256 241.356814 +L 207.232924 240.76989 +L 207.537592 239.889503 +L 208.146929 240.113915 +L 208.451597 241.097877 +L 208.756265 241.253239 +L 209.67027 241.115139 +L 209.974939 241.719326 +L 210.584275 241.771114 +L 210.888943 241.494914 +L 211.193612 241.771114 +L 212.107617 241.788376 +L 212.412285 240.890727 +L 212.716953 240.372853 +L 213.021622 241.771114 +L 213.32629 240.873465 +L 213.630958 240.90799 +L 213.935627 240.597265 +L 214.240295 240.545477 +L 214.544963 241.443127 +L 214.849631 240.63179 +L 215.1543 240.252015 +L 215.763636 240.044865 +L 216.068305 241.149664 +L 216.372973 241.080614 +L 216.677641 240.804415 +L 216.98231 241.132402 +L 217.286978 241.132402 +L 217.591646 241.391339 +L 218.200983 241.391339 +L 218.505651 241.097877 +L 218.810319 240.338328 +L 219.114988 241.771114 +L 219.419656 241.719326 +L 219.724324 241.374077 +L 220.028993 240.476427 +L 220.333661 240.42464 +L 220.638329 241.771114 +L 221.247666 240.027603 +L 221.552334 240.545477 +L 221.857002 240.459165 +L 222.161671 241.477652 +L 222.466339 240.113915 +L 222.771007 239.94129 +L 223.075676 240.234753 +L 223.380344 240.269278 +L 223.685012 240.925252 +L 224.903686 240.856202 +L 225.208354 241.253239 +L 225.513022 241.201452 +L 226.122359 241.322289 +L 226.427027 241.287764 +L 226.731695 241.615752 +L 227.036364 241.546702 +L 227.950369 241.719326 +L 228.864373 241.529439 +L 229.169042 241.546702 +L 229.47371 241.235977 +L 229.778378 241.512177 +L 230.083047 240.994302 +L 230.997052 240.321065 +L 231.30172 241.201452 +L 232.520393 241.132402 +L 232.825061 241.477652 +L 233.12973 241.512177 +L 233.434398 241.425864 +L 233.739066 241.563964 +L 234.043735 241.546702 +L 234.348403 241.736589 +L 234.653071 241.598489 +L 235.262408 241.581227 +L 235.567076 240.76989 +L 235.871744 241.857426 +L 236.176413 241.822901 +L 236.481081 241.322289 +L 236.785749 241.235977 +L 237.090418 240.994302 +L 237.395086 241.719326 +L 238.004423 241.149664 +L 238.309091 240.372853 +L 238.613759 240.113915 +L 238.918428 240.649052 +L 239.223096 240.70084 +L 239.527764 240.614527 +L 239.832432 240.683577 +L 240.441769 240.56274 +L 240.746437 240.735365 +L 241.051106 240.666315 +L 241.660442 240.252015 +L 241.965111 240.614527 +L 242.574447 240.338328 +L 242.879115 240.459165 +L 243.183784 240.28654 +L 243.488452 240.683577 +L 243.79312 240.735365 +L 244.097789 240.269278 +L 244.402457 240.338328 +L 244.707125 240.14844 +L 245.316462 240.994302 +L 245.62113 240.873465 +L 245.925799 240.303803 +L 246.230467 240.165703 +L 246.535135 240.407378 +L 247.753808 240.372853 +L 248.058477 240.735365 +L 249.581818 240.683577 +L 250.191155 240.49369 +L 250.495823 240.597265 +L 250.800491 240.165703 +L 251.10516 241.080614 +L 251.409828 240.959777 +L 251.714496 240.580002 +L 252.019165 240.614527 +L 252.323833 240.407378 +L 252.628501 241.04609 +L 252.93317 240.70084 +L 253.237838 240.044865 +L 253.542506 240.459165 +L 253.847174 240.597265 +L 254.151843 241.391339 +L 254.456511 241.581227 +L 255.065848 241.408602 +L 255.370516 241.425864 +L 255.675184 241.598489 +L 257.807862 241.615752 +L 258.112531 241.425864 +L 258.417199 241.097877 +L 258.721867 241.719326 +L 259.026536 241.460389 +L 259.331204 241.529439 +L 259.635872 240.56274 +L 259.940541 240.614527 +L 260.245209 241.633014 +L 261.159214 240.90799 +L 261.463882 240.683577 +L 261.76855 241.080614 +L 262.073219 240.994302 +L 262.377887 241.080614 +L 262.682555 241.011565 +L 262.987224 241.184189 +L 263.291892 241.063352 +L 263.901229 241.115139 +L 264.205897 240.752627 +L 264.510565 240.890727 +L 264.815233 241.339552 +L 265.42457 241.253239 +L 266.033907 240.07939 +L 266.338575 241.512177 +L 266.643243 240.873465 +L 266.947912 241.063352 +L 267.25258 240.63179 +L 267.557248 240.459165 +L 267.861916 241.322289 +L 268.166585 240.76989 +L 268.471253 239.958553 +L 268.775921 240.200228 +L 269.08059 240.200228 +L 269.385258 241.650277 +L 271.213268 241.633014 +L 271.822604 241.598489 +L 272.127273 240.252015 +L 272.431941 241.356814 +L 273.041278 240.959777 +L 273.650614 239.87224 +L 273.955283 241.822901 +L 274.564619 240.407378 +L 275.173956 240.42464 +L 275.478624 241.650277 +L 276.087961 240.56274 +L 276.697297 240.182965 +L 277.001966 241.494914 +L 277.306634 241.546702 +L 277.611302 241.408602 +L 277.915971 241.667539 +L 278.220639 241.477652 +L 279.134644 241.374077 +L 279.439312 241.581227 +L 279.74398 240.372853 +L 280.048649 241.408602 +L 280.353317 241.408602 +L 280.657985 241.080614 +L 280.962654 240.062128 +L 281.267322 239.958553 +L 281.57199 241.909214 +L 281.876658 241.563964 +L 282.181327 240.856202 +L 282.485995 240.70084 +L 282.790663 240.735365 +L 283.095332 241.719326 +L 283.4 241.04609 +L 283.704668 240.07939 +L 284.009337 240.28654 +L 284.314005 240.131178 +L 284.618673 241.322289 +L 285.837346 241.339552 +L 286.142015 241.891951 +L 286.446683 241.978264 +L 287.05602 241.961001 +L 287.360688 240.925252 +L 287.665356 241.667539 +L 287.970025 241.598489 +L 288.274693 241.287764 +L 288.579361 240.35559 +L 288.884029 240.821677 +L 289.188698 242.012789 +L 289.798034 241.011565 +L 290.102703 240.804415 +L 290.407371 240.459165 +L 290.712039 241.667539 +L 291.016708 241.391339 +L 291.321376 240.56274 +L 291.626044 240.735365 +L 291.930713 240.70084 +L 292.235381 241.374077 +L 292.540049 241.443127 +L 293.149386 241.339552 +L 293.454054 241.408602 +L 293.758722 241.753851 +L 294.368059 241.667539 +L 294.977396 241.736589 +L 295.8914 241.736589 +L 296.500737 240.804415 +L 296.805405 242.047314 +L 297.110074 242.030051 +L 297.414742 241.753851 +L 298.024079 240.56274 +L 298.328747 242.064576 +L 298.938084 240.735365 +L 299.242752 240.528215 +L 299.54742 241.218714 +L 299.852088 241.270502 +L 300.156757 241.149664 +L 300.461425 241.322289 +L 301.070762 241.080614 +L 301.37543 241.546702 +L 302.289435 241.477652 +L 302.594103 241.097877 +L 302.898771 241.736589 +L 303.20344 241.753851 +L 303.508108 241.425864 +L 303.812776 240.459165 +L 304.422113 241.805639 +L 304.726781 241.891951 +L 305.03145 240.83894 +L 305.336118 240.83894 +L 305.640786 241.719326 +L 305.945455 241.684801 +L 306.250123 241.788376 +L 306.859459 240.407378 +L 307.164128 240.752627 +L 307.468796 242.047314 +L 307.773464 241.736589 +L 308.687469 241.702064 +L 308.992138 242.030051 +L 309.906143 242.047314 +L 310.210811 241.04609 +L 310.515479 242.064576 +L 311.124816 242.064576 +L 311.429484 241.149664 +L 311.734152 240.649052 +L 312.038821 241.995526 +L 312.343489 241.771114 +L 312.952826 241.080614 +L 313.257494 240.890727 +L 313.562162 241.978264 +L 313.86683 241.408602 +L 314.171499 240.476427 +L 314.780835 240.580002 +L 315.085504 241.097877 +L 315.999509 241.149664 +L 316.304177 241.166927 +L 316.608845 241.494914 +L 317.218182 241.529439 +L 319.046192 241.615752 +L 319.35086 241.063352 +L 319.655528 241.926476 +L 320.264865 241.978264 +L 320.569533 242.116364 +L 320.874201 240.90799 +L 321.17887 241.840164 +L 321.483538 241.857426 +L 321.788206 241.546702 +L 322.702211 241.270502 +L 323.00688 241.512177 +L 323.311548 241.477652 +L 323.616216 241.581227 +L 323.920885 241.374077 +L 324.225553 240.97704 +L 324.530221 241.563964 +L 324.834889 241.391339 +L 325.444226 241.339552 +L 325.748894 241.270502 +L 326.053563 241.581227 +L 326.358231 241.339552 +L 326.967568 241.339552 +L 327.272236 241.235977 +L 327.576904 241.650277 +L 328.186241 241.287764 +L 328.795577 241.305027 +L 329.100246 241.857426 +L 329.404914 241.356814 +L 330.014251 241.805639 +L 330.318919 241.115139 +L 330.623587 241.805639 +L 330.928256 241.270502 +L 331.537592 241.270502 +L 331.84226 241.080614 +L 332.146929 241.563964 +L 332.451597 241.425864 +L 332.756265 241.563964 +L 333.365602 241.115139 +L 333.67027 241.529439 +L 333.974939 241.287764 +L 334.279607 241.391339 +L 334.888943 241.166927 +L 335.193612 241.667539 +L 335.49828 241.253239 +L 336.107617 241.235977 +L 336.412285 241.063352 +L 336.716953 241.736589 +L 337.021622 241.322289 +L 337.32629 241.529439 +L 337.630958 241.563964 +L 337.935627 241.166927 +L 338.240295 241.477652 +L 338.544963 241.149664 +L 338.849631 241.512177 +L 339.458968 241.149664 +L 339.763636 241.615752 +L 340.068305 240.890727 +L 340.372973 241.529439 +L 340.677641 241.650277 +L 340.98231 241.460389 +L 341.286978 241.512177 +L 341.591646 241.166927 +L 341.896314 241.529439 +L 342.200983 241.633014 +L 342.505651 241.581227 +L 342.810319 241.840164 +L 343.114988 241.563964 +L 343.419656 241.805639 +L 343.724324 241.840164 +L 344.028993 241.287764 +L 344.333661 241.529439 +L 344.638329 241.270502 +L 344.942998 241.460389 +L 345.247666 241.097877 +L 345.857002 241.719326 +L 346.466339 241.408602 +L 346.771007 241.633014 +L 347.075676 241.719326 +L 347.380344 241.477652 +L 347.685012 241.753851 +L 347.989681 241.460389 +L 348.599017 241.581227 +L 348.903686 241.425864 +L 349.208354 241.633014 +L 349.513022 241.460389 +L 349.81769 241.460389 +L 350.122359 241.650277 +L 350.731695 241.615752 +L 351.341032 241.408602 +L 351.6457 241.909214 +L 351.950369 241.633014 +L 352.255037 241.753851 +L 352.559705 241.287764 +L 352.864373 241.097877 +L 353.169042 241.615752 +L 353.778378 241.512177 +L 354.083047 241.253239 +L 354.387715 241.356814 +L 354.692383 241.650277 +L 354.997052 241.391339 +L 355.606388 241.356814 +L 355.911057 241.270502 +L 356.215725 241.788376 +L 356.520393 241.201452 +L 357.12973 240.925252 +L 357.434398 241.166927 +L 357.739066 241.753851 +L 358.348403 241.235977 +L 358.653071 241.322289 +L 358.95774 241.028827 +L 359.262408 241.909214 +L 359.567076 241.529439 +L 359.871744 241.477652 +L 360.176413 241.598489 +L 360.481081 241.374077 +L 360.785749 241.633014 +L 361.090418 241.512177 +L 361.395086 241.581227 +L 361.699754 241.529439 +L 362.004423 241.753851 +L 362.309091 241.546702 +L 362.613759 241.702064 +L 362.918428 241.494914 +L 363.223096 241.443127 +L 363.527764 241.633014 +L 363.832432 241.598489 +L 364.137101 241.391339 +L 365.051106 241.633014 +L 365.965111 241.339552 +L 366.269779 241.650277 +L 366.574447 241.477652 +L 367.183784 241.512177 +L 367.79312 241.305027 +L 368.097789 241.408602 +L 368.402457 241.201452 +L 369.62113 241.063352 +L 369.925799 241.460389 +L 370.535135 241.132402 +L 370.839803 241.218714 +L 371.144472 240.873465 +L 371.44914 241.287764 +L 371.753808 241.270502 +L 372.058477 241.011565 +L 372.363145 241.063352 +L 372.667813 240.942515 +L 372.972482 241.235977 +L 373.27715 241.201452 +L 373.581818 241.028827 +L 373.581818 241.028827 +" clip-path="url(#pdceb6906fc)" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> + </g> + <g id="line2d_15"> + <path d="M 69.218182 236.972143 +L 69.52285 236.903093 +L 69.827518 235.522094 +L 70.132187 235.901869 +L 70.741523 234.969694 +L 71.046192 235.677456 +L 71.35086 235.625669 +L 71.655528 238.629341 +L 71.960197 44.495424 +L 72.569533 44.478161 +L 73.17887 44.478161 +L 73.483538 236.298906 +L 73.788206 237.990629 +L 74.092875 238.007892 +L 74.397543 233.260708 +L 74.702211 233.571433 +L 75.00688 221.159706 +L 75.920885 229.152237 +L 76.225553 44.598999 +L 76.530221 44.443636 +L 78.662899 44.495424 +L 79.272236 44.443636 +L 79.576904 230.291561 +L 79.881572 44.478161 +L 80.795577 44.478161 +L 81.100246 44.460899 +L 81.404914 216.101797 +L 81.709582 218.328658 +L 82.014251 235.228632 +L 82.318919 44.478161 +L 83.232924 44.512686 +L 83.537592 241.166927 +L 83.84226 241.184189 +L 84.146929 241.425864 +L 84.756265 241.529439 +L 85.974939 241.408602 +L 86.584275 241.391339 +L 86.888943 241.132402 +L 88.107617 241.063352 +L 88.412285 241.512177 +L 88.716953 241.529439 +L 89.32629 241.408602 +L 90.849631 241.512177 +L 91.1543 241.080614 +L 91.458968 241.011565 +L 91.763636 241.115139 +L 92.068305 241.028827 +L 92.372973 241.149664 +L 93.591646 241.115139 +L 94.200983 241.04609 +L 94.505651 241.391339 +L 94.810319 241.063352 +L 95.724324 241.149664 +L 96.028993 241.04609 +L 96.333661 241.374077 +L 96.942998 241.529439 +L 97.247666 241.011565 +L 97.552334 241.132402 +L 97.857002 241.011565 +L 98.161671 241.028827 +L 98.466339 241.408602 +L 98.771007 241.425864 +L 99.075676 241.581227 +L 99.685012 241.443127 +L 101.81769 241.460389 +L 103.6457 241.460389 +L 105.47371 241.546702 +L 105.778378 241.425864 +L 107.30172 241.443127 +L 108.520393 241.391339 +L 109.12973 241.443127 +L 109.434398 241.581227 +L 110.043735 241.425864 +L 111.262408 241.425864 +L 111.567076 241.546702 +L 111.871744 241.546702 +L 112.481081 241.391339 +L 112.785749 44.926986 +L 113.090418 44.443636 +L 113.699754 44.478161 +L 114.004423 237.006668 +L 114.309091 236.644156 +L 114.613759 235.832819 +L 114.918428 236.782255 +L 115.527764 236.057231 +L 115.832432 236.81678 +L 116.137101 236.95488 +L 116.441769 239.043641 +L 116.746437 44.512686 +L 117.965111 44.478161 +L 118.269779 237.09298 +L 118.574447 238.076942 +L 118.879115 238.094204 +L 119.183784 233.864895 +L 119.488452 234.31372 +L 119.79312 222.040092 +L 120.097789 224.991978 +L 120.402457 225.924152 +L 120.707125 229.980836 +L 121.011794 44.581736 +L 121.316462 44.443636 +L 124.058477 44.495424 +L 124.363145 233.381546 +L 124.667813 44.460899 +L 125.886486 44.460899 +L 126.191155 216.18811 +L 126.495823 217.810783 +L 126.800491 235.901869 +L 127.10516 44.547211 +L 127.714496 44.460899 +L 128.019165 44.495424 +L 128.323833 238.991854 +L 128.628501 239.060904 +L 128.93317 241.477652 +L 129.237838 241.563964 +L 130.151843 241.494914 +L 131.370516 241.443127 +L 131.675184 239.147216 +L 131.979853 238.871016 +L 132.893857 238.991854 +L 133.198526 241.546702 +L 133.503194 241.581227 +L 133.807862 241.425864 +L 135.635872 241.563964 +L 135.940541 239.078166 +L 136.245209 238.940066 +L 136.549877 239.112691 +L 138.682555 239.043641 +L 138.987224 238.991854 +L 139.291892 241.529439 +L 139.59656 239.147216 +L 139.901229 238.940066 +L 140.205897 239.009116 +L 140.815233 239.268053 +L 141.119902 241.477652 +L 141.729238 241.598489 +L 142.033907 239.199004 +L 142.338575 239.216266 +L 142.643243 238.801966 +L 142.947912 239.526991 +L 143.25258 241.011565 +L 143.557248 241.080614 +L 143.861916 241.529439 +L 145.385258 241.460389 +L 145.994595 241.494914 +L 146.299263 241.563964 +L 146.603931 241.028827 +L 146.9086 240.90799 +L 147.517936 240.994302 +L 147.822604 241.028827 +L 148.127273 241.425864 +L 148.736609 241.581227 +L 150.564619 241.356814 +L 150.869287 240.942515 +L 151.173956 240.873465 +L 152.087961 240.97704 +L 153.915971 240.959777 +L 154.220639 241.563964 +L 154.525307 241.04609 +L 155.134644 240.90799 +L 155.74398 241.028827 +L 156.048649 241.443127 +L 156.657985 241.546702 +L 156.962654 241.011565 +L 157.267322 240.925252 +L 157.876658 240.372853 +L 158.181327 240.925252 +L 158.485995 241.028827 +L 158.790663 241.305027 +L 159.095332 241.270502 +L 159.4 241.408602 +L 159.704668 241.305027 +L 161.22801 241.477652 +L 161.532678 241.04609 +L 161.837346 241.028827 +L 162.142015 241.132402 +L 162.446683 241.115139 +L 162.751351 240.90799 +L 163.360688 241.460389 +L 163.970025 241.287764 +L 165.188698 241.460389 +L 165.493366 241.356814 +L 165.798034 240.97704 +L 166.102703 240.942515 +L 166.407371 241.115139 +L 167.016708 240.90799 +L 167.321376 240.97704 +L 167.930713 240.90799 +L 168.235381 241.063352 +L 168.844717 240.925252 +L 169.149386 241.443127 +L 169.454054 240.90799 +L 170.063391 241.063352 +L 170.368059 241.080614 +L 170.672727 240.97704 +L 170.977396 241.253239 +L 171.586732 241.477652 +L 171.8914 241.04609 +L 172.196069 241.097877 +L 172.500737 240.873465 +L 173.110074 241.253239 +L 176.461425 241.374077 +L 176.766093 241.235977 +L 178.898771 241.443127 +L 179.508108 241.322289 +L 180.726781 241.374077 +L 181.03145 241.218714 +L 181.640786 241.287764 +L 182.554791 241.218714 +L 183.773464 241.235977 +L 184.078133 241.443127 +L 184.687469 241.201452 +L 185.296806 241.201452 +L 185.906143 241.287764 +L 186.210811 241.425864 +L 186.515479 241.425864 +L 187.124816 241.253239 +L 187.429484 45.237711 +L 187.734152 44.668049 +L 188.343489 44.771624 +L 188.648157 236.488793 +L 188.952826 236.367956 +L 189.257494 235.660194 +L 189.562162 236.695943 +L 189.86683 236.730468 +L 190.171499 236.229856 +L 190.476167 236.799518 +L 190.780835 236.402481 +L 191.085504 237.679905 +L 191.390172 44.857936 +L 191.69484 44.737099 +L 191.999509 44.840674 +L 192.304177 44.788886 +L 192.608845 44.961511 +L 192.913514 237.524542 +L 193.218182 239.233528 +L 193.52285 239.129954 +L 193.827518 232.691046 +L 194.132187 233.329758 +L 194.436855 222.350817 +L 194.741523 225.371752 +L 195.046192 226.683701 +L 195.35086 230.136198 +L 195.655528 44.996036 +L 195.960197 44.668049 +L 196.264865 44.806149 +L 196.569533 44.685311 +L 197.788206 44.702574 +L 198.092875 44.909723 +L 198.397543 44.719836 +L 198.702211 44.754361 +L 199.00688 232.328534 +L 199.311548 44.771624 +L 199.616216 44.633524 +L 199.920885 44.633524 +L 200.530221 44.823411 +L 200.834889 215.463085 +L 201.139558 216.619672 +L 201.444226 234.917907 +L 201.748894 44.771624 +L 202.358231 44.737099 +L 202.662899 44.771624 +L 202.967568 241.201452 +L 204.490909 241.322289 +L 204.795577 241.218714 +L 205.404914 241.322289 +L 206.318919 241.356814 +L 206.623587 241.218714 +L 207.537592 241.356814 +L 210.584275 241.305027 +L 210.888943 241.184189 +L 211.802948 241.201452 +L 213.630958 241.218714 +L 213.935627 241.391339 +L 214.544963 241.201452 +L 215.458968 241.253239 +L 216.372973 241.443127 +L 216.98231 241.235977 +L 217.286978 240.90799 +L 217.896314 240.890727 +L 218.200983 241.04609 +L 218.505651 241.391339 +L 219.114988 241.322289 +L 219.419656 241.374077 +L 219.724324 241.235977 +L 220.333661 241.408602 +L 220.638329 241.270502 +L 220.942998 241.287764 +L 221.247666 240.942515 +L 221.552334 240.890727 +L 221.857002 241.011565 +L 222.466339 240.97704 +L 222.771007 241.408602 +L 223.075676 241.391339 +L 223.685012 241.184189 +L 224.294349 241.356814 +L 224.903686 241.253239 +L 225.208354 241.339552 +L 225.513022 240.994302 +L 225.81769 240.873465 +L 227.950369 240.90799 +L 228.559705 240.821677 +L 228.864373 241.201452 +L 229.169042 240.804415 +L 230.083047 240.873465 +L 230.387715 240.735365 +L 230.692383 241.115139 +L 230.997052 241.287764 +L 231.30172 241.305027 +L 231.606388 240.752627 +L 231.911057 240.856202 +L 232.520393 240.70084 +L 232.825061 241.028827 +L 233.434398 241.201452 +L 233.739066 241.115139 +L 234.348403 241.235977 +L 234.653071 241.132402 +L 234.95774 241.253239 +L 235.262408 241.166927 +L 235.871744 241.287764 +L 236.481081 241.080614 +L 238.613759 241.270502 +L 239.223096 241.132402 +L 239.832432 241.184189 +L 240.137101 241.132402 +L 240.441769 241.218714 +L 240.746437 241.028827 +L 241.355774 241.097877 +L 243.488452 241.028827 +L 243.79312 241.218714 +L 244.402457 240.994302 +L 245.316462 241.04609 +L 246.230467 241.184189 +L 246.839803 240.97704 +L 247.144472 240.614527 +L 247.44914 240.545477 +L 248.667813 241.184189 +L 249.581818 241.080614 +L 249.886486 241.149664 +L 250.495823 241.080614 +L 250.800491 241.080614 +L 251.10516 240.787152 +L 251.714496 240.718102 +L 252.019165 240.787152 +L 252.323833 240.718102 +L 252.628501 241.115139 +L 252.93317 241.201452 +L 253.237838 241.063352 +L 255.065848 241.201452 +L 255.370516 240.821677 +L 255.675184 240.735365 +L 255.979853 240.83894 +L 256.589189 240.718102 +L 257.807862 240.890727 +L 258.417199 240.76989 +L 258.721867 241.149664 +L 259.026536 240.821677 +L 259.331204 240.752627 +L 259.940541 240.873465 +L 260.245209 240.787152 +L 260.549877 241.063352 +L 261.159214 241.218714 +L 261.463882 240.76989 +L 261.76855 240.873465 +L 262.073219 44.978773 +L 262.377887 44.443636 +L 262.987224 44.460899 +L 263.291892 236.972143 +L 263.901229 235.763769 +L 264.205897 235.539356 +L 264.510565 235.746506 +L 264.815233 235.090532 +L 265.119902 236.039969 +L 265.42457 235.988181 +L 265.729238 237.973367 +L 266.033907 44.460899 +L 267.25258 44.478161 +L 267.557248 236.523318 +L 267.861916 237.904317 +L 268.166585 238.076942 +L 268.471253 234.676232 +L 268.775921 234.917907 +L 269.08059 223.058579 +L 269.385258 225.613427 +L 269.689926 226.735489 +L 269.994595 229.652849 +L 270.299263 44.581736 +L 270.603931 44.443636 +L 273.345946 44.443636 +L 273.650614 229.549274 +L 273.955283 44.512686 +L 275.173956 44.443636 +L 275.478624 216.015485 +L 275.783292 217.137546 +L 276.087961 234.900644 +L 276.392629 44.512686 +L 277.001966 44.460899 +L 277.306634 44.547211 +L 277.611302 241.011565 +L 277.915971 241.028827 +L 278.220639 241.322289 +L 280.657985 241.270502 +L 280.962654 240.994302 +L 281.876658 240.959777 +L 282.181327 241.028827 +L 282.485995 241.322289 +L 284.923342 241.270502 +L 285.532678 240.959777 +L 286.446683 240.97704 +L 288.274693 240.97704 +L 288.579361 241.287764 +L 289.493366 240.942515 +L 290.407371 241.115139 +L 290.712039 241.270502 +L 291.016708 241.287764 +L 291.321376 241.011565 +L 291.626044 240.97704 +L 291.930713 240.56274 +L 292.235381 240.441902 +L 292.540049 240.718102 +L 292.844717 240.735365 +L 293.149386 241.270502 +L 293.758722 241.097877 +L 295.586732 241.218714 +L 295.8914 240.752627 +L 296.500737 240.666315 +L 297.110074 240.70084 +L 297.414742 241.063352 +L 298.024079 241.115139 +L 298.328747 241.235977 +L 298.938084 241.080614 +L 299.242752 241.097877 +L 299.54742 241.235977 +L 300.461425 240.70084 +L 303.20344 240.718102 +L 303.508108 241.253239 +L 303.812776 240.752627 +L 304.422113 240.683577 +L 305.03145 240.752627 +L 305.336118 241.115139 +L 305.640786 241.270502 +L 305.945455 241.270502 +L 306.250123 240.76989 +L 306.554791 240.752627 +L 306.859459 44.926986 +L 307.164128 44.495424 +L 307.773464 44.495424 +L 308.078133 235.591144 +L 308.687469 234.17562 +L 308.992138 234.883382 +L 309.296806 234.900644 +L 309.601474 234.38277 +L 309.906143 235.245894 +L 310.210811 235.038744 +L 310.515479 237.16203 +L 310.820147 44.529949 +L 311.429484 44.529949 +L 312.038821 44.547211 +L 312.343489 235.936394 +L 312.648157 237.43823 +L 312.952826 237.835267 +L 313.257494 232.345797 +L 313.562162 232.760096 +L 313.86683 220.572781 +L 314.780835 226.942638 +L 315.085504 44.616261 +L 315.390172 44.495424 +L 318.132187 44.478161 +L 318.436855 230.947535 +L 318.741523 44.512686 +L 319.655528 44.495424 +L 319.960197 44.512686 +L 320.264865 215.91191 +L 320.569533 217.914358 +L 320.874201 234.330982 +L 321.17887 44.581736 +L 321.788206 44.512686 +L 322.092875 44.529949 +L 322.397543 241.097877 +L 323.311548 241.235977 +L 323.920885 241.235977 +L 324.834889 241.218714 +L 325.444226 241.322289 +L 326.053563 241.201452 +L 327.272236 241.218714 +L 327.881572 241.322289 +L 328.490909 241.253239 +L 329.100246 241.235977 +L 330.928256 241.166927 +L 331.537592 241.097877 +L 333.67027 241.132402 +L 334.888943 241.149664 +L 335.802948 241.270502 +L 336.412285 241.115139 +L 336.716953 237.78348 +L 337.021622 237.30013 +L 337.630958 237.541805 +L 337.935627 241.132402 +L 339.1543 241.166927 +L 340.068305 241.218714 +L 340.372973 241.132402 +L 340.677641 237.593592 +L 340.98231 237.455492 +L 341.591646 237.490017 +L 341.896314 237.731692 +L 342.200983 241.097877 +L 342.505651 241.305027 +L 343.114988 241.097877 +L 344.028993 241.235977 +L 344.333661 241.374077 +L 344.638329 241.235977 +L 344.942998 237.731692 +L 345.247666 237.541805 +L 345.552334 237.662642 +L 345.857002 237.403705 +L 347.380344 237.593592 +L 347.685012 237.628117 +L 347.989681 237.50728 +L 348.294349 241.322289 +L 348.599017 237.64538 +L 349.208354 237.43823 +L 349.513022 237.541805 +L 349.81769 237.800742 +L 350.122359 241.184189 +L 350.731695 241.391339 +L 351.036364 237.904317 +L 351.341032 237.766217 +L 351.6457 237.351917 +L 351.950369 238.059679 +L 352.255037 241.04609 +L 352.559705 241.04609 +L 352.864373 241.305027 +L 353.47371 241.391339 +L 354.083047 241.322289 +L 355.30172 241.287764 +L 355.606388 241.011565 +L 356.215725 240.97704 +L 356.520393 241.011565 +L 356.825061 240.90799 +L 357.12973 241.356814 +L 357.434398 241.374077 +L 357.739066 241.253239 +L 359.262408 241.356814 +L 359.567076 241.408602 +L 359.871744 240.994302 +L 360.176413 240.925252 +L 360.481081 241.04609 +L 360.785749 240.890727 +L 361.395086 240.925252 +L 361.699754 240.873465 +L 362.309091 240.942515 +L 362.918428 240.856202 +L 363.223096 241.201452 +L 363.527764 240.890727 +L 364.746437 240.873465 +L 365.051106 241.132402 +L 365.660442 241.287764 +L 365.965111 240.856202 +L 366.269779 240.97704 +L 366.574447 240.545477 +L 366.879115 240.649052 +L 367.183784 240.614527 +L 368.402457 241.218714 +L 368.707125 241.132402 +L 369.316462 241.287764 +L 369.62113 241.149664 +L 369.925799 241.201452 +L 370.230467 241.132402 +L 370.535135 240.683577 +L 370.839803 240.597265 +L 371.144472 240.735365 +L 371.753808 240.597265 +L 372.058477 241.028827 +L 372.363145 241.201452 +L 372.667813 241.063352 +L 373.27715 241.097877 +L 373.581818 241.184189 +L 373.581818 241.184189 +" clip-path="url(#pdceb6906fc)" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> + </g> + <g id="patch_3"> + <path d="M 54 252 +L 54 34.56 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="patch_4"> + <path d="M 388.8 252 +L 388.8 34.56 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="patch_5"> + <path d="M 54 252 +L 388.8 252 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="patch_6"> + <path d="M 54 34.56 +L 388.8 34.56 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="text_15"> + <!-- Parameter Values --> + <g transform="translate(168.675 28.56)scale(0.12 -0.12)"> + <defs> + <path id="DejaVuSans-56" d="M 1831 0 +L 50 4666 +L 709 4666 +L 2188 738 +L 3669 4666 +L 4325 4666 +L 2547 0 +L 1831 0 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-6c" d="M 603 4863 +L 1178 4863 +L 1178 0 +L 603 0 +L 603 4863 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-75" d="M 544 1381 +L 544 3500 +L 1119 3500 +L 1119 1403 +Q 1119 906 1312 657 +Q 1506 409 1894 409 +Q 2359 409 2629 706 +Q 2900 1003 2900 1516 +L 2900 3500 +L 3475 3500 +L 3475 0 +L 2900 0 +L 2900 538 +Q 2691 219 2414 64 +Q 2138 -91 1772 -91 +Q 1169 -91 856 284 +Q 544 659 544 1381 +z +M 1991 3584 +L 1991 3584 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-50"/> + <use xlink:href="#DejaVuSans-61" x="55.802734"/> + <use xlink:href="#DejaVuSans-72" x="117.082031"/> + <use xlink:href="#DejaVuSans-61" x="158.195312"/> + <use xlink:href="#DejaVuSans-6d" x="219.474609"/> + <use xlink:href="#DejaVuSans-65" x="316.886719"/> + <use xlink:href="#DejaVuSans-74" x="378.410156"/> + <use xlink:href="#DejaVuSans-65" x="417.619141"/> + <use xlink:href="#DejaVuSans-72" x="479.142578"/> + <use xlink:href="#DejaVuSans-20" x="520.255859"/> + <use xlink:href="#DejaVuSans-56" x="552.042969"/> + <use xlink:href="#DejaVuSans-61" x="612.701172"/> + <use xlink:href="#DejaVuSans-6c" x="673.980469"/> + <use xlink:href="#DejaVuSans-75" x="701.763672"/> + <use xlink:href="#DejaVuSans-65" x="765.142578"/> + <use xlink:href="#DejaVuSans-73" x="826.666016"/> + </g> + </g> + <g id="legend_1"> + <g id="patch_7"> + <path d="M 276.029688 159.458125 +L 381.8 159.458125 +Q 383.8 159.458125 383.8 157.458125 +L 383.8 129.101875 +Q 383.8 127.101875 381.8 127.101875 +L 276.029688 127.101875 +Q 274.029688 127.101875 274.029688 129.101875 +L 274.029688 157.458125 +Q 274.029688 159.458125 276.029688 159.458125 +z +" style="fill: #ffffff; opacity: 0.8; stroke: #cccccc; stroke-linejoin: miter"/> + </g> + <g id="line2d_16"> + <path d="M 278.029688 135.200312 +L 288.029688 135.200312 +L 298.029688 135.200312 +" style="fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square"/> + </g> + <g id="text_16"> + <!-- top-10% --> + <g transform="translate(306.029688 138.700312)scale(0.1 -0.1)"> + <defs> + <path id="DejaVuSans-6f" d="M 1959 3097 +Q 1497 3097 1228 2736 +Q 959 2375 959 1747 +Q 959 1119 1226 758 +Q 1494 397 1959 397 +Q 2419 397 2687 759 +Q 2956 1122 2956 1747 +Q 2956 2369 2687 2733 +Q 2419 3097 1959 3097 +z +M 1959 3584 +Q 2709 3584 3137 3096 +Q 3566 2609 3566 1747 +Q 3566 888 3137 398 +Q 2709 -91 1959 -91 +Q 1206 -91 779 398 +Q 353 888 353 1747 +Q 353 2609 779 3096 +Q 1206 3584 1959 3584 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-70" d="M 1159 525 +L 1159 -1331 +L 581 -1331 +L 581 3500 +L 1159 3500 +L 1159 2969 +Q 1341 3281 1617 3432 +Q 1894 3584 2278 3584 +Q 2916 3584 3314 3078 +Q 3713 2572 3713 1747 +Q 3713 922 3314 415 +Q 2916 -91 2278 -91 +Q 1894 -91 1617 61 +Q 1341 213 1159 525 +z +M 3116 1747 +Q 3116 2381 2855 2742 +Q 2594 3103 2138 3103 +Q 1681 3103 1420 2742 +Q 1159 2381 1159 1747 +Q 1159 1113 1420 752 +Q 1681 391 2138 391 +Q 2594 391 2855 752 +Q 3116 1113 3116 1747 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-2d" d="M 313 2009 +L 1997 2009 +L 1997 1497 +L 313 1497 +L 313 2009 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-25" d="M 4653 2053 +Q 4381 2053 4226 1822 +Q 4072 1591 4072 1178 +Q 4072 772 4226 539 +Q 4381 306 4653 306 +Q 4919 306 5073 539 +Q 5228 772 5228 1178 +Q 5228 1588 5073 1820 +Q 4919 2053 4653 2053 +z +M 4653 2450 +Q 5147 2450 5437 2106 +Q 5728 1763 5728 1178 +Q 5728 594 5436 251 +Q 5144 -91 4653 -91 +Q 4153 -91 3862 251 +Q 3572 594 3572 1178 +Q 3572 1766 3864 2108 +Q 4156 2450 4653 2450 +z +M 1428 4353 +Q 1159 4353 1004 4120 +Q 850 3888 850 3481 +Q 850 3069 1003 2837 +Q 1156 2606 1428 2606 +Q 1700 2606 1854 2837 +Q 2009 3069 2009 3481 +Q 2009 3884 1853 4118 +Q 1697 4353 1428 4353 +z +M 4250 4750 +L 4750 4750 +L 1831 -91 +L 1331 -91 +L 4250 4750 +z +M 1428 4750 +Q 1922 4750 2215 4408 +Q 2509 4066 2509 3481 +Q 2509 2891 2217 2550 +Q 1925 2209 1428 2209 +Q 931 2209 642 2551 +Q 353 2894 353 3481 +Q 353 4063 643 4406 +Q 934 4750 1428 4750 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-74"/> + <use xlink:href="#DejaVuSans-6f" x="39.208984"/> + <use xlink:href="#DejaVuSans-70" x="100.390625"/> + <use xlink:href="#DejaVuSans-2d" x="163.867188"/> + <use xlink:href="#DejaVuSans-31" x="199.951172"/> + <use xlink:href="#DejaVuSans-30" x="263.574219"/> + <use xlink:href="#DejaVuSans-25" x="327.197266"/> + </g> + </g> + <g id="line2d_17"> + <path d="M 278.029688 149.878437 +L 288.029688 149.878437 +L 298.029688 149.878437 +" style="fill: none; stroke: #ff7f0e; stroke-width: 1.5; stroke-linecap: square"/> + </g> + <g id="text_17"> + <!-- Sym2 top-10% --> + <g transform="translate(306.029688 153.378437)scale(0.1 -0.1)"> + <defs> + <path id="DejaVuSans-53" d="M 3425 4513 +L 3425 3897 +Q 3066 4069 2747 4153 +Q 2428 4238 2131 4238 +Q 1616 4238 1336 4038 +Q 1056 3838 1056 3469 +Q 1056 3159 1242 3001 +Q 1428 2844 1947 2747 +L 2328 2669 +Q 3034 2534 3370 2195 +Q 3706 1856 3706 1288 +Q 3706 609 3251 259 +Q 2797 -91 1919 -91 +Q 1588 -91 1214 -16 +Q 841 59 441 206 +L 441 856 +Q 825 641 1194 531 +Q 1563 422 1919 422 +Q 2459 422 2753 634 +Q 3047 847 3047 1241 +Q 3047 1584 2836 1778 +Q 2625 1972 2144 2069 +L 1759 2144 +Q 1053 2284 737 2584 +Q 422 2884 422 3419 +Q 422 4038 858 4394 +Q 1294 4750 2059 4750 +Q 2388 4750 2728 4690 +Q 3069 4631 3425 4513 +z +" transform="scale(0.015625)"/> + <path id="DejaVuSans-79" d="M 2059 -325 +Q 1816 -950 1584 -1140 +Q 1353 -1331 966 -1331 +L 506 -1331 +L 506 -850 +L 844 -850 +Q 1081 -850 1212 -737 +Q 1344 -625 1503 -206 +L 1606 56 +L 191 3500 +L 800 3500 +L 1894 763 +L 2988 3500 +L 3597 3500 +L 2059 -325 +z +" transform="scale(0.015625)"/> + </defs> + <use xlink:href="#DejaVuSans-53"/> + <use xlink:href="#DejaVuSans-79" x="63.476562"/> + <use xlink:href="#DejaVuSans-6d" x="122.65625"/> + <use xlink:href="#DejaVuSans-32" x="220.068359"/> + <use xlink:href="#DejaVuSans-20" x="283.691406"/> + <use xlink:href="#DejaVuSans-74" x="315.478516"/> + <use xlink:href="#DejaVuSans-6f" x="354.6875"/> + <use xlink:href="#DejaVuSans-70" x="415.869141"/> + <use xlink:href="#DejaVuSans-2d" x="479.345703"/> + <use xlink:href="#DejaVuSans-31" x="515.429688"/> + <use xlink:href="#DejaVuSans-30" x="579.052734"/> + <use xlink:href="#DejaVuSans-25" x="642.675781"/> + </g> + </g> + </g> + </g> + </g> + <defs> + <clipPath id="pdceb6906fc"> + <rect x="54" y="34.56" width="334.8" height="217.44"/> + </clipPath> + </defs> +</svg> diff --git a/random files/ParametersWaveletHaarAcc.png b/random files/ParametersWaveletHaarAcc.png new file mode 100644 index 0000000000000000000000000000000000000000..08c1ba7cc2068fbe3dca1317f50aab8ec4ad0483 Binary files /dev/null and b/random files/ParametersWaveletHaarAcc.png differ diff --git a/random files/PartialModel.py b/random files/PartialModel.py new file mode 100644 index 0000000000000000000000000000000000000000..5fccc99b48836ba361da3bcf390d561a036e7a01 --- /dev/null +++ b/random files/PartialModel.py @@ -0,0 +1,381 @@ +import json +import logging +import os +from pathlib import Path + +import numpy as np +import torch + +from decentralizepy.sharing.Sharing import Sharing +from decentralizepy.utils import conditional_value, identity + + +class PartialModel(Sharing): + """ + This class implements the vanilla version of partial model sharing. + + """ + + def __init__( + self, + rank, + machine_id, + communication, + mapping, + graph, + model, + dataset, + log_dir, + alpha=1.0, + dict_ordered=True, + save_shared=False, + metadata_cap=1.0, + accumulation=False, + save_accumulated="", + change_transformer=identity, + accumulate_averaging_changes=False, + ): + """ + Constructor + + Parameters + ---------- + rank : int + Local rank + machine_id : int + Global machine id + communication : decentralizepy.communication.Communication + Communication module used to send and receive messages + mapping : decentralizepy.mappings.Mapping + Mapping (rank, machine_id) -> uid + graph : decentralizepy.graphs.Graph + Graph reprensenting neighbors + model : decentralizepy.models.Model + Model to train + dataset : decentralizepy.datasets.Dataset + Dataset for sharing data. Not implemented yet! TODO + log_dir : str + Location to write shared_params (only writing for 2 procs per machine) + alpha : float + Percentage of model to share + dict_ordered : bool + Specifies if the python dict maintains the order of insertion + save_shared : bool + Specifies if the indices of shared parameters should be logged + metadata_cap : float + Share full model when self.alpha > metadata_cap + accumulation : bool + True if the the indices to share should be selected based on accumulated frequency change + save_accumulated : bool + True if accumulated weight change should be written to file. In case of accumulation the accumulated change + is stored. If a change_transformer is used then the transformed change is stored. + change_transformer : (x: Tensor) -> Tensor + A function that transforms the model change into other domains. Default: identity function + accumulate_averaging_changes: bool + True if the accumulation should account the model change due to averaging + + """ + super().__init__( + rank, machine_id, communication, mapping, graph, model, dataset, log_dir + ) + self.alpha = alpha + self.dict_ordered = dict_ordered + self.save_shared = save_shared + self.metadata_cap = metadata_cap + self.total_meta = 0 + self.accumulation = accumulation + self.save_accumulated = conditional_value(save_accumulated, "", False) + self.change_transformer = change_transformer + self.accumulate_averaging_changes = accumulate_averaging_changes + + # getting the initial model + self.shapes = [] + self.lens = [] + with torch.no_grad(): + tensors_to_cat = [] + for _, v in self.model.state_dict().items(): + self.shapes.append(v.shape) + t = v.flatten() + self.lens.append(t.shape[0]) + tensors_to_cat.append(t) + self.init_model = torch.cat(tensors_to_cat, dim=0) + if self.accumulation: + self.model.accumulated_changes = torch.zeros_like( + self.change_transformer(self.init_model) + ) + self.prev = self.init_model + + if self.save_accumulated: + self.model_change_path = os.path.join( + self.log_dir, "model_change/{}".format(self.rank) + ) + Path(self.model_change_path).mkdir(parents=True, exist_ok=True) + + self.model_val_path = os.path.join( + self.log_dir, "model_val/{}".format(self.rank) + ) + Path(self.model_val_path).mkdir(parents=True, exist_ok=True) + + # Only save for 2 procs: Save space + if self.save_shared and not (rank == 0 or rank == 1): + self.save_shared = False + + if self.save_shared: + self.folder_path = os.path.join( + self.log_dir, "shared_params/{}".format(self.rank) + ) + Path(self.folder_path).mkdir(parents=True, exist_ok=True) + + self.model.shared_parameters_counter = torch.zeros( + self.change_transformer(self.init_model).shape[0], dtype=torch.int32 + ) + + self.caches = dict() + my_neighbors = self.graph.neighbors(self.uid) + for n in my_neighbors: + self.caches[n] = self.init_model.clone().detach() + self.my_uid = self.mapping.get_uid(self.rank, self.machine_id) + self.caches[self.my_uid] = self.init_model.clone().detach() + self.e = torch.zeros_like(self.init_model) + + def extract_top_gradients(self): + """ + Extract the indices and values of the topK gradients. + The gradients must have been accumulated. + + Returns + ------- + tuple + (a,b). a: The magnitudes of the topK gradients, b: Their indices. + + """ + + logging.info("Returning topk gradients") + G_topk = torch.abs(self.u) + std, mean = torch.std_mean(G_topk, unbiased=False) + self.std = std.item() + self.mean = mean.item() + return torch.topk( + G_topk, round(self.alpha * G_topk.shape[0]), dim=0, sorted=False + ) + + def serialized_model(self): + """ + Convert model to a dict. self.alpha specifies the fraction of model to send. + + Returns + ------- + dict + Model converted to a dict + + """ + if self.alpha >= self.metadata_cap: # Share fully + return super().serialized_model() + + with torch.no_grad(): + _, G_topk = self.extract_top_gradients() + self.model.shared_parameters_counter[G_topk] += 1 + + start_index = 0 + std_dict = {} + new_model = self.init_model.clone().detach() + new_model[G_topk] += self.u[G_topk] + self.caches[self.my_uid] = new_model.clone().detach() + for i, key in enumerate(self.model.state_dict()): + end_index = start_index + self.lens[i] + std_dict[key] = new_model[start_index:end_index].reshape(self.shapes[i]) + start_index = end_index + + self.model.load_state_dict(std_dict) + self.g[G_topk] -= self.g[G_topk] + self.e = self.g + + if self.save_shared: + shared_params = dict() + shared_params["order"] = list(self.model.state_dict().keys()) + shapes = dict() + for k, v in self.model.state_dict().items(): + shapes[k] = list(v.shape) + shared_params["shapes"] = shapes + + shared_params[self.communication_round] = G_topk.tolist() + + with open( + os.path.join( + self.folder_path, + "{}_shared_params.json".format(self.communication_round + 1), + ), + "w", + ) as of: + json.dump(shared_params, of) + + logging.info("Extracting topk params") + + logging.info("Generating dictionary to send") + + m = dict() + + if not self.dict_ordered: + raise NotImplementedError + + m["indices"] = G_topk.numpy().astype(np.int32) + + m["params"] = self.u[G_topk].numpy() + + m["send_partial"] = True + + assert len(m["indices"]) == len(m["params"]) + logging.info("Elements sending: {}".format(len(m["indices"]))) + + logging.info("Generated dictionary to send") + + logging.info("Converted dictionary to pickle") + self.total_data += len(self.communication.encrypt(m["params"])) + self.total_meta += len(self.communication.encrypt(m["indices"])) + + return m + + def deserialized_model(self, m): + """ + Convert received dict to state_dict. + + Parameters + ---------- + m : dict + dict received + + Returns + ------- + state_dict + state_dict of received + + """ + if "send_partial" not in m: + return super().deserialized_model(m) + + with torch.no_grad(): + state_dict = self.model.state_dict() + + if not self.dict_ordered: + raise NotImplementedError + + index_tensor = torch.tensor(m["indices"], dtype=torch.long) + values = torch.tensor(m["params"]) + return index_tensor, values + + def _pre_step(self): + """ + Called at the beginning of step. + + """ + tensors_to_cat = [v.data.flatten() for _, v in self.model.state_dict().items()] + self.post_train_model = torch.cat(tensors_to_cat, dim=0) + self.g = self.e + (self.post_train_model - self.init_model) + + def _averaging(self): + """ + Averages the received model with the local model + + """ + with torch.no_grad(): + total = torch.zeros_like(self.init_model) + weight_total = 0 + for i, n in enumerate(self.caches): + if n != self.my_uid: + data = self.caches[n] + degree = len(self.graph.neighbors(n)) + weight = 1 / ( + max(len(self.peer_deques), degree) + 1 + ) # Metro-Hastings + weight_total += weight + total += data * weight + + total += (1 - weight_total) * self.caches[self.my_uid] # Metro-Hastings + self.avg = total + + def step(self): + """ + Perform a sharing step. Implements D-PSGD. + + """ + + self._pre_step() + + logging.info("Starting model averaging after receiving from all neighbors") + self._averaging() + logging.info("Model averaging complete") + + self.u = (self.avg - self.init_model) - self.g + + data = self.serialized_model() + my_uid = self.mapping.get_uid(self.rank, self.machine_id) + all_neighbors = self.graph.neighbors(my_uid) + iter_neighbors = self.get_neighbors(all_neighbors) + data["degree"] = len(all_neighbors) + data["iteration"] = self.communication_round + for neighbor in iter_neighbors: + self.communication.send(neighbor, data) + + logging.info("Waiting for messages from neighbors") + while not self.received_from_all(): + sender, data = self.communication.receive() + logging.debug("Received model from {}".format(sender)) + degree = data["degree"] + iteration = data["iteration"] + del data["degree"] + del data["iteration"] + self.peer_deques[sender].append((degree, iteration, data)) + logging.info( + "Deserialized received model from {} of iteration {}".format( + sender, iteration + ) + ) + + for i, n in enumerate(self.peer_deques): + degree, iteration, data = self.peer_deques[n].popleft() + ind, val = self.deserialized_model(data) + self.caches[n][ind] += val + + self.communication_round += 1 + + tensors_to_cat = [v.data.flatten() for _, v in self.model.state_dict().items()] + post_share_model = torch.cat(tensors_to_cat, dim=0) + self.init_model = post_share_model + self._post_step() + + def save_vector(self, v, s): + """ + Saves the given vector to the file. + + Parameters + ---------- + v : torch.tensor + The torch tensor to write to file + s : str + Path to folder to write to + + """ + output_dict = dict() + output_dict["order"] = list(self.model.state_dict().keys()) + shapes = dict() + for k, v1 in self.model.state_dict().items(): + shapes[k] = list(v1.shape) + output_dict["shapes"] = shapes + + output_dict["tensor"] = v.tolist() + + with open( + os.path.join( + s, + "{}.json".format(self.communication_round + 1), + ), + "w", + ) as of: + json.dump(output_dict, of) + + def save_change(self): + """ + Saves the change and the gradient values for every iteration + + """ + self.save_vector(self.model.model_change, self.model_change_path) diff --git a/random files/PartialModelWed.py b/random files/PartialModelWed.py new file mode 100644 index 0000000000000000000000000000000000000000..5fccc99b48836ba361da3bcf390d561a036e7a01 --- /dev/null +++ b/random files/PartialModelWed.py @@ -0,0 +1,381 @@ +import json +import logging +import os +from pathlib import Path + +import numpy as np +import torch + +from decentralizepy.sharing.Sharing import Sharing +from decentralizepy.utils import conditional_value, identity + + +class PartialModel(Sharing): + """ + This class implements the vanilla version of partial model sharing. + + """ + + def __init__( + self, + rank, + machine_id, + communication, + mapping, + graph, + model, + dataset, + log_dir, + alpha=1.0, + dict_ordered=True, + save_shared=False, + metadata_cap=1.0, + accumulation=False, + save_accumulated="", + change_transformer=identity, + accumulate_averaging_changes=False, + ): + """ + Constructor + + Parameters + ---------- + rank : int + Local rank + machine_id : int + Global machine id + communication : decentralizepy.communication.Communication + Communication module used to send and receive messages + mapping : decentralizepy.mappings.Mapping + Mapping (rank, machine_id) -> uid + graph : decentralizepy.graphs.Graph + Graph reprensenting neighbors + model : decentralizepy.models.Model + Model to train + dataset : decentralizepy.datasets.Dataset + Dataset for sharing data. Not implemented yet! TODO + log_dir : str + Location to write shared_params (only writing for 2 procs per machine) + alpha : float + Percentage of model to share + dict_ordered : bool + Specifies if the python dict maintains the order of insertion + save_shared : bool + Specifies if the indices of shared parameters should be logged + metadata_cap : float + Share full model when self.alpha > metadata_cap + accumulation : bool + True if the the indices to share should be selected based on accumulated frequency change + save_accumulated : bool + True if accumulated weight change should be written to file. In case of accumulation the accumulated change + is stored. If a change_transformer is used then the transformed change is stored. + change_transformer : (x: Tensor) -> Tensor + A function that transforms the model change into other domains. Default: identity function + accumulate_averaging_changes: bool + True if the accumulation should account the model change due to averaging + + """ + super().__init__( + rank, machine_id, communication, mapping, graph, model, dataset, log_dir + ) + self.alpha = alpha + self.dict_ordered = dict_ordered + self.save_shared = save_shared + self.metadata_cap = metadata_cap + self.total_meta = 0 + self.accumulation = accumulation + self.save_accumulated = conditional_value(save_accumulated, "", False) + self.change_transformer = change_transformer + self.accumulate_averaging_changes = accumulate_averaging_changes + + # getting the initial model + self.shapes = [] + self.lens = [] + with torch.no_grad(): + tensors_to_cat = [] + for _, v in self.model.state_dict().items(): + self.shapes.append(v.shape) + t = v.flatten() + self.lens.append(t.shape[0]) + tensors_to_cat.append(t) + self.init_model = torch.cat(tensors_to_cat, dim=0) + if self.accumulation: + self.model.accumulated_changes = torch.zeros_like( + self.change_transformer(self.init_model) + ) + self.prev = self.init_model + + if self.save_accumulated: + self.model_change_path = os.path.join( + self.log_dir, "model_change/{}".format(self.rank) + ) + Path(self.model_change_path).mkdir(parents=True, exist_ok=True) + + self.model_val_path = os.path.join( + self.log_dir, "model_val/{}".format(self.rank) + ) + Path(self.model_val_path).mkdir(parents=True, exist_ok=True) + + # Only save for 2 procs: Save space + if self.save_shared and not (rank == 0 or rank == 1): + self.save_shared = False + + if self.save_shared: + self.folder_path = os.path.join( + self.log_dir, "shared_params/{}".format(self.rank) + ) + Path(self.folder_path).mkdir(parents=True, exist_ok=True) + + self.model.shared_parameters_counter = torch.zeros( + self.change_transformer(self.init_model).shape[0], dtype=torch.int32 + ) + + self.caches = dict() + my_neighbors = self.graph.neighbors(self.uid) + for n in my_neighbors: + self.caches[n] = self.init_model.clone().detach() + self.my_uid = self.mapping.get_uid(self.rank, self.machine_id) + self.caches[self.my_uid] = self.init_model.clone().detach() + self.e = torch.zeros_like(self.init_model) + + def extract_top_gradients(self): + """ + Extract the indices and values of the topK gradients. + The gradients must have been accumulated. + + Returns + ------- + tuple + (a,b). a: The magnitudes of the topK gradients, b: Their indices. + + """ + + logging.info("Returning topk gradients") + G_topk = torch.abs(self.u) + std, mean = torch.std_mean(G_topk, unbiased=False) + self.std = std.item() + self.mean = mean.item() + return torch.topk( + G_topk, round(self.alpha * G_topk.shape[0]), dim=0, sorted=False + ) + + def serialized_model(self): + """ + Convert model to a dict. self.alpha specifies the fraction of model to send. + + Returns + ------- + dict + Model converted to a dict + + """ + if self.alpha >= self.metadata_cap: # Share fully + return super().serialized_model() + + with torch.no_grad(): + _, G_topk = self.extract_top_gradients() + self.model.shared_parameters_counter[G_topk] += 1 + + start_index = 0 + std_dict = {} + new_model = self.init_model.clone().detach() + new_model[G_topk] += self.u[G_topk] + self.caches[self.my_uid] = new_model.clone().detach() + for i, key in enumerate(self.model.state_dict()): + end_index = start_index + self.lens[i] + std_dict[key] = new_model[start_index:end_index].reshape(self.shapes[i]) + start_index = end_index + + self.model.load_state_dict(std_dict) + self.g[G_topk] -= self.g[G_topk] + self.e = self.g + + if self.save_shared: + shared_params = dict() + shared_params["order"] = list(self.model.state_dict().keys()) + shapes = dict() + for k, v in self.model.state_dict().items(): + shapes[k] = list(v.shape) + shared_params["shapes"] = shapes + + shared_params[self.communication_round] = G_topk.tolist() + + with open( + os.path.join( + self.folder_path, + "{}_shared_params.json".format(self.communication_round + 1), + ), + "w", + ) as of: + json.dump(shared_params, of) + + logging.info("Extracting topk params") + + logging.info("Generating dictionary to send") + + m = dict() + + if not self.dict_ordered: + raise NotImplementedError + + m["indices"] = G_topk.numpy().astype(np.int32) + + m["params"] = self.u[G_topk].numpy() + + m["send_partial"] = True + + assert len(m["indices"]) == len(m["params"]) + logging.info("Elements sending: {}".format(len(m["indices"]))) + + logging.info("Generated dictionary to send") + + logging.info("Converted dictionary to pickle") + self.total_data += len(self.communication.encrypt(m["params"])) + self.total_meta += len(self.communication.encrypt(m["indices"])) + + return m + + def deserialized_model(self, m): + """ + Convert received dict to state_dict. + + Parameters + ---------- + m : dict + dict received + + Returns + ------- + state_dict + state_dict of received + + """ + if "send_partial" not in m: + return super().deserialized_model(m) + + with torch.no_grad(): + state_dict = self.model.state_dict() + + if not self.dict_ordered: + raise NotImplementedError + + index_tensor = torch.tensor(m["indices"], dtype=torch.long) + values = torch.tensor(m["params"]) + return index_tensor, values + + def _pre_step(self): + """ + Called at the beginning of step. + + """ + tensors_to_cat = [v.data.flatten() for _, v in self.model.state_dict().items()] + self.post_train_model = torch.cat(tensors_to_cat, dim=0) + self.g = self.e + (self.post_train_model - self.init_model) + + def _averaging(self): + """ + Averages the received model with the local model + + """ + with torch.no_grad(): + total = torch.zeros_like(self.init_model) + weight_total = 0 + for i, n in enumerate(self.caches): + if n != self.my_uid: + data = self.caches[n] + degree = len(self.graph.neighbors(n)) + weight = 1 / ( + max(len(self.peer_deques), degree) + 1 + ) # Metro-Hastings + weight_total += weight + total += data * weight + + total += (1 - weight_total) * self.caches[self.my_uid] # Metro-Hastings + self.avg = total + + def step(self): + """ + Perform a sharing step. Implements D-PSGD. + + """ + + self._pre_step() + + logging.info("Starting model averaging after receiving from all neighbors") + self._averaging() + logging.info("Model averaging complete") + + self.u = (self.avg - self.init_model) - self.g + + data = self.serialized_model() + my_uid = self.mapping.get_uid(self.rank, self.machine_id) + all_neighbors = self.graph.neighbors(my_uid) + iter_neighbors = self.get_neighbors(all_neighbors) + data["degree"] = len(all_neighbors) + data["iteration"] = self.communication_round + for neighbor in iter_neighbors: + self.communication.send(neighbor, data) + + logging.info("Waiting for messages from neighbors") + while not self.received_from_all(): + sender, data = self.communication.receive() + logging.debug("Received model from {}".format(sender)) + degree = data["degree"] + iteration = data["iteration"] + del data["degree"] + del data["iteration"] + self.peer_deques[sender].append((degree, iteration, data)) + logging.info( + "Deserialized received model from {} of iteration {}".format( + sender, iteration + ) + ) + + for i, n in enumerate(self.peer_deques): + degree, iteration, data = self.peer_deques[n].popleft() + ind, val = self.deserialized_model(data) + self.caches[n][ind] += val + + self.communication_round += 1 + + tensors_to_cat = [v.data.flatten() for _, v in self.model.state_dict().items()] + post_share_model = torch.cat(tensors_to_cat, dim=0) + self.init_model = post_share_model + self._post_step() + + def save_vector(self, v, s): + """ + Saves the given vector to the file. + + Parameters + ---------- + v : torch.tensor + The torch tensor to write to file + s : str + Path to folder to write to + + """ + output_dict = dict() + output_dict["order"] = list(self.model.state_dict().keys()) + shapes = dict() + for k, v1 in self.model.state_dict().items(): + shapes[k] = list(v1.shape) + output_dict["shapes"] = shapes + + output_dict["tensor"] = v.tolist() + + with open( + os.path.join( + s, + "{}.json".format(self.communication_round + 1), + ), + "w", + ) as of: + json.dump(output_dict, of) + + def save_change(self): + """ + Saves the change and the gradient values for every iteration + + """ + self.save_vector(self.model.model_change, self.model_change_path) diff --git a/random files/WVFreq_Diff_Values.png b/random files/WVFreq_Diff_Values.png new file mode 100644 index 0000000000000000000000000000000000000000..48954e2293cc2e105bb2eaa7c32a20df709bd91e Binary files /dev/null and b/random files/WVFreq_Diff_Values.png differ diff --git a/random files/WVFreq_Values.png b/random files/WVFreq_Values.png new file mode 100644 index 0000000000000000000000000000000000000000..ee8f7ce2d6d0951098a75e86fcf01eb99d17f87d Binary files /dev/null and b/random files/WVFreq_Values.png differ diff --git a/random files/accHist.png b/random files/accHist.png new file mode 100644 index 0000000000000000000000000000000000000000..6d14866f13987e00fa5de2ec071fd07e7462e59d Binary files /dev/null and b/random files/accHist.png differ diff --git a/random files/accPercentiles.png b/random files/accPercentiles.png new file mode 100644 index 0000000000000000000000000000000000000000..71aea29b6fbadfc71eb99f4d48726be4ccdaba62 Binary files /dev/null and b/random files/accPercentiles.png differ diff --git a/random files/accPercentiles70.png b/random files/accPercentiles70.png new file mode 100644 index 0000000000000000000000000000000000000000..60175b0f7eff376e436ca78a314bd4e461fadaa9 Binary files /dev/null and b/random files/accPercentiles70.png differ diff --git a/random files/celeba.ipynb b/random files/celeba.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..14aa8d39e80bf44968a2381323fe1be79209b238 --- /dev/null +++ b/random files/celeba.ipynb @@ -0,0 +1,768 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZMZYcW3itMzT", + "outputId": "f2970f7e-cf26-4a67-e8d3-29bcd1a11775" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2VftlLfttdT8", + "outputId": "48b47fdc-853b-4711-ae95-8c0e64510615" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "ft7BMl1LyWP6" + }, + "outputs": [], + "source": [ + "from torch import nn\n", + "import torch\n", + "import os\n", + "import json\n", + "import pickle\n", + "import numpy as np\n", + "import pywt\n", + "train_dir = \"./../\"\n", + "my_train_data = {\"x\": [], \"y\": []}" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<torch._C.Generator at 0x7f9ed4066cd0>" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.manual_seed(13)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "hi0N5rB5xBWn" + }, + "outputs": [], + "source": [ + "if torch.cuda.is_available():\n", + " device = \"cuda\"\n", + "else:\n", + " device = \"cpu\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "6lO3uYsmxNYz", + "outputId": "b170b610-f21e-465d-fcd6-b7e6989e73e5" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'cpu'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "device" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Contents\n", + "* [CNN Model Training](#train)\n", + "* [Optimizer analysis](#optim)\n", + "* [FFT](#fft)\n", + "* [Wavelets](#wt)\n", + "* [FFT Training](#ffttrain)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CNN Model Training <a class=\"anchor\" id=\"train\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "9LpgzEw1s-xo" + }, + "outputs": [], + "source": [ + "# From Femnist.py\n", + "def read_file(file_path):\n", + " with open(file_path, \"r\") as inf:\n", + " client_data = json.load(inf)\n", + " print(\"loaded the data\")\n", + " return (\n", + " client_data[\"users\"],\n", + " client_data[\"num_samples\"],\n", + " client_data[\"user_data\"],\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QBu1kiw8s-xr" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "raw", + "metadata": { + "id": "jI3ixEN4s-xt", + "outputId": "ed969663-9e1e-4810-9507-52cdc426650a" + }, + "source": [ + "# From Femnist.py\n", + "for i in range(1):\n", + " cur_file = \"leaf/data/femnist/data/train/all_data_0_niid_0_keep_0_train_9.json\"\n", + " # test_file = \"leaf/data/femnist/data/test/all_data_0_niid_0_keep_0_test_9.json\"\n", + " # cur_file = test_file\n", + " clients, _, train_data = read_file(\n", + " os.path.join(train_dir, cur_file)\n", + " )\n", + " for cur_client in clients:\n", + " # self.clients.append(cur_client)\n", + " my_train_data[\"x\"].extend(train_data[cur_client][\"x\"])\n", + " my_train_data[\"y\"].extend(train_data[cur_client][\"y\"])\n", + " del train_data[cur_client]\n" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "wvHsSz8as-xw" + }, + "source": [ + "train_x = (\n", + " np.array(my_train_data[\"x\"], dtype=np.dtype(\"float32\"))\n", + " .reshape(-1, 28, 28, 1)\n", + " .transpose(0, 3, 1, 2)\n", + ")\n", + "train_y = np.array(my_train_data[\"y\"], dtype=np.dtype(\"int64\")).reshape(-1)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "K8X471SKs-xz", + "outputId": "cdf73c06-1323-4e76-850b-16324008d255" + }, + "source": [ + "len(train_y)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "EpWNELBrs-x0" + }, + "source": [ + "with open(train_dir+\"femnist.pkl\", \"wb\") as f:\n", + " pickle.dump({\"test_x\": train_x, \"test_y\": train_y}, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mAEASHr2s-x1" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "Am_XlcSSs-x3" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "evAd9ZvYs-x6" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "9_vIFakbs-x7", + "outputId": "3a8b546a-186f-4519-8c0b-e853986a8101" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856, 1, 28, 28)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_x\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "GPyZ2C8ws-x9" + }, + "outputs": [], + "source": [ + "IMAGE_DIM = 84\n", + "CHANNELS = 3\n", + "NUM_CLASSES = 2\n", + "import torch.nn.functional as F\n", + "\n", + "class CNN(nn.Module):\n", + " \"\"\"\n", + " Class for a CNN Model for Celeba\n", + "\n", + " \"\"\"\n", + "\n", + " def __init__(self):\n", + " \"\"\"\n", + " Constructor. Instantiates the CNN Model\n", + " with 84*84*3 Input and 2 output classes\n", + "\n", + " \"\"\"\n", + " super().__init__()\n", + " # 2.8k parameters\n", + " self.conv1 = nn.Conv2d(CHANNELS, 32, 3, padding=\"same\")\n", + " self.pool = nn.MaxPool2d(2, 2)\n", + " self.conv2 = nn.Conv2d(32, 32, 3, padding=\"same\")\n", + " self.conv3 = nn.Conv2d(32, 32, 3, padding=\"same\")\n", + " self.conv4 = nn.Conv2d(32, 32, 3, padding=\"same\")\n", + " self.fc1 = nn.Linear(5 * 5 * 32, NUM_CLASSES)\n", + "\n", + " def forward(self, x):\n", + " \"\"\"\n", + " Forward pass of the model\n", + "\n", + " Parameters\n", + " ----------\n", + " x : torch.tensor\n", + " The input torch tensor\n", + "\n", + " Returns\n", + " -------\n", + " torch.tensor\n", + " The output torch tensor\n", + "\n", + " \"\"\"\n", + " x = F.relu(self.pool(self.conv1(x)))\n", + " x = F.relu(self.pool(self.conv2(x)))\n", + " x = F.relu(self.pool(self.conv3(x)))\n", + " x = F.relu(self.pool(self.conv4(x)))\n", + " x = torch.flatten(x, 1)\n", + " x = self.fc1(x)\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bCgW8ClBs-x_" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "oBGwcwZks-yA" + }, + "outputs": [], + "source": [ + "import os\n", + "from torch.utils.data import Dataset\n", + "\n", + "class FemnistDataset(Dataset):\n", + " def __init__(self, training, transform=None, target_transform=None):\n", + " if training:\n", + " with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)\n", + " self.data = train[\"train_x\"]\n", + " self.label = train[\"train_y\"]\n", + " else: \n", + " with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)\n", + " self.data = test[\"test_x\"]\n", + " self.label = test[\"test_y\"]\n", + " self.transform = transform\n", + " self.target_transform = target_transform\n", + "\n", + " def __len__(self):\n", + " return len(self.label)\n", + "\n", + " def __getitem__(self, idx):\n", + " return self.data[idx], self.label[idx]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "U3boC_N4s-yC" + }, + "outputs": [], + "source": [ + "from torch.utils.data import DataLoader" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "sJsrQXkEs-yD" + }, + "outputs": [], + "source": [ + "trainset = FemnistDataset(True)\n", + "testset = FemnistDataset(False)\n", + "\n", + "train_dataloader = DataLoader(trainset, batch_size=128, shuffle=True)\n", + "test_dataloader = DataLoader(testset, batch_size=128, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5749" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(train_dataloader)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "735872" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "5749*128" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "id": "e65Izyv0s-yE" + }, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1714, -0.1405, -0.0313, 0.0578, 0.0766, -0.1935, 0.1538, 0.0907,\n", + " 0.0226, 0.0708, 0.1525, -0.0412, -0.1595, 0.0278, 0.0404, -0.1018,\n", + " -0.1330, -0.1515, -0.1124, 0.0592, -0.0866, -0.0707, -0.0435, -0.0559,\n", + " 0.0480, -0.1483, -0.0215, -0.1404, -0.0433, 0.0631, -0.1822, -0.0755])" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "tensor([-0.0180, 0.0236, 0.1279, -0.1352, -0.1948, -0.0330, -0.1615, -0.0286,\n", + " -0.1762, 0.0040, 0.1570, -0.1069, -0.1074, -0.1417, -0.1171, 0.0359,\n", + " 0.1276, -0.1534, -0.1773, -0.1639, 0.1334, 0.0518, 0.0586, 0.1466,\n", + " 0.1283, 0.0443, -0.0982, -0.1739, -0.0061, 0.1047, -0.0291, 0.1525])" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([32, 1, 5, 5])\n", + "torch.Size([32])\n", + "torch.Size([64, 32, 5, 5])\n", + "torch.Size([64])\n", + "torch.Size([512, 3136])\n", + "torch.Size([512])\n", + "torch.Size([62, 512])\n", + "torch.Size([62])\n" + ] + } + ], + "source": [ + "for p in model.parameters():\n", + " print(p.data.size())\n", + " p.data = torch.zeros(p.data.size())" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0.])" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "eqOXilqMs-yF", + "outputId": "06799a3b-983b-4f51-a7bd-a901c041bd05" + }, + "outputs": [], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(10):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "id": "4P-VA0vcs-yH" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"/results:128:\"+str(lr)+\".pkl\", \"wb\") as f:\n", + " pickle.dump(stats, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "641-b_VCvT2b", + "outputId": "cced38ab-5c04-45b2-faf4-e73327126159" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "F_OKqiiHs-yJ", + "outputId": "65786b88-05f4-42fa-a851-03397ef4457a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.1: [9. 3.69780584 5.50521373]\n", + "0.01: [ 9. 3.98475619 82.61967193]\n", + "0.005: [ 9. 0.51492128 85.40642722]\n", + "0.001: [ 9. 0.41047618 88.03829502]\n", + "0.0005: [ 9. 0.44351858 88.21025672]\n", + "0.0001: [ 9. 0.67233266 87.71754375]\n", + "1e-05: [ 9. 1.81167539 81.52570279]\n" + ] + } + ], + "source": [ + "lrs = [0.1, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00001]\n", + "for l in lrs:\n", + " with open(train_dir+\"/results:128:\"+str(l)+\".pkl\", \"rb\") as f:\n", + " res = pickle.load(f)\n", + " print(str(l)+\": \" + str(np.amax(res[\"test\"], axis=0)))#+ str(np.max(res[\"test\"]))\n", + " # print(str(l)+\": \" + str(res[\"test\"]))\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rADw-XkfKjOo", + "outputId": "06c54a2c-f7c2-4610-f879-3e1c2f98543f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.1: [[0, 3.6898819485246297, 4.914933837429111], [1, 3.695287103771977, 4.914933837429111], [2, 3.691172517592003, 5.505213732544667], [3, 3.6920483804158226, 4.967376059515824], [4, 3.6939517986755845, 5.505213732544667], [5, 3.6917366434742993, 4.914933837429111], [6, 3.695435837910811, 5.505213732544667], [7, 3.6978058357506574, 5.135679004817367], [8, 3.6948341036363623, 5.505213732544667], [9, 3.6921330658768343, 5.135679004817367]]\n", + "0.01: [[0, 0.5728003431500958, 81.8086468687115], [1, 0.5517885946725348, 82.61967193121532], [2, 3.984756194857093, 25.844258796268065], [3, 0.5739870879932797, 81.7476675407037], [4, 0.7832032613188912, 75.77779132873955], [5, 0.7142617320772638, 77.80474419171901], [6, 0.6602287095348103, 79.28654186230868], [7, 0.6738644539380036, 79.2719068235868], [8, 0.6469118589079138, 79.77071772669065], [9, 0.6788249858734946, 79.28898103542899]]\n", + "0.005: [[0, 0.4834194714537649, 83.79047502896519], [1, 0.466142692822562, 84.33928898103544], [2, 0.4559767278791776, 84.9515214342338], [3, 0.4488265364432298, 84.86493078846271], [4, 0.4554814101660307, 84.773461796451], [5, 0.5149212768315897, 83.05872309287152], [6, 0.4551808235472338, 84.86127202878224], [7, 0.4531376465992325, 85.06494298432831], [8, 0.4589428385362238, 84.83078236477834], [9, 0.4409179601951992, 85.40642722117202]]\n", + "0.001: [[0, 0.4104761779773254, 85.89670101835478], [1, 0.36889259526491536, 87.17604731995854], [2, 0.3517718464717292, 87.6992499542655], [3, 0.35526543692939927, 87.57607171168974], [4, 0.3493265717198808, 87.76266845539362], [5, 0.35079776836259874, 87.47362644063662], [6, 0.34534544340812845, 87.96268065125923], [7, 0.35734797465540874, 87.72608085858894], [8, 0.3524193228360457, 87.63339228001708], [9, 0.35447056082407136, 88.0382950179889]]\n", + "0.0005: [[0, 0.4435185831906085, 85.1039697542533], [1, 0.37539843543085405, 86.94310628696871], [2, 0.35873422210283473, 87.3797182755046], [3, 0.34818319706667605, 87.93097140069517], [4, 0.34545205666010914, 87.86633331300689], [5, 0.3371337376732536, 88.10415269223734], [6, 0.33852135716659976, 88.11512897127874], [7, 0.33852605533302293, 88.14074028904201], [8, 0.33997187332225476, 88.21025672297091], [9, 0.3402654077747311, 88.1968412708092]]\n", + "0.0001: [[0, 0.6723326555745278, 79.72437343740472], [1, 0.5084800024207409, 83.89901823281907], [2, 0.45863669222676995, 84.88932251966584], [3, 0.42524330169194946, 85.90767729739618], [4, 0.4028480564841242, 86.33575218001097], [5, 0.38621816764383715, 86.9126166229648], [6, 0.3782781209337544, 87.11506799195074], [7, 0.3759017101781045, 87.00530520153667], [8, 0.3668581307538772, 87.32117812061712], [9, 0.3569657983208967, 87.71754375266785]]\n", + "1e-05: [[0, 1.8116753936371826, 54.021586682114766], [1, 1.3575628893609724, 63.8148667601683], [2, 1.0996285610935432, 69.48716385145435], [3, 0.9349309672803477, 73.7788889566437], [4, 0.8294046315685635, 76.08878590157937], [5, 0.7614829346374863, 77.91938532837368], [6, 0.7032811826737176, 79.30727483383133], [7, 0.6657257149818349, 80.09024940545156], [8, 0.6363296165202226, 80.82931886090616], [9, 0.6094131586890139, 81.52570278675529]]\n" + ] + } + ], + "source": [ + "lrs = [0.1, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00001]\n", + "for l in lrs:\n", + " with open(train_dir+\"/results:128:\"+str(l)+\".pkl\", \"rb\") as f:\n", + " res = pickle.load(f)\n", + " # print(str(l)+\": \" + str(np.amax(res[\"test\"], axis=0)))#+ str(np.max(res[\"test\"]))\n", + " print(str(l)+\": \" + str(res[\"test\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HGpNYzG_s-yJ", + "outputId": "783622a5-249f-4dd8-d242-fc6dfa47443c" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using cache found in /home/jeffrey/.cache/torch/hub/pytorch_vision_v0.10.0\n" + ] + } + ], + "source": [ + "import torch\n", + "resnet = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uZFgT6wss-yL", + "outputId": "10f8fc51-abb7-4c2b-f608-85229f3de29d", + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11699132\n" + ] + } + ], + "source": [ + "total = 0\n", + "for i in resnet.state_dict().values():\n", + " total += i.flatten().size(dim=0)\n", + "print(total)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizer analysis <a class=\"anchor\" id=\"optim\"></a>" + ] + } + ], + "metadata": { + "colab": { + "name": "learningrate.ipynb", + "provenance": [] + }, + "interpreter": { + "hash": "996934296aa9d79be6c3d800a38d8fdb7dfa8fe7bb07df178f1397cde2cb8742" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/random files/generate_graph.py b/random files/generate_graph.py new file mode 100644 index 0000000000000000000000000000000000000000..cd625424844ad9d4d95aa885da311bd6bc76dbfb --- /dev/null +++ b/random files/generate_graph.py @@ -0,0 +1,19 @@ +import matplotlib.pyplot as plt +import networkx as nx + +from decentralizepy.graphs.Regular import Regular +from decentralizepy.graphs.Ring import Ring +from decentralizepy.graphs.Star import Star + +# b = Regular(16, 1, 686) + + +b = Regular(96*3, 5) +# TODO: rewrite to directly connect dissconnected subgraphs +# b.connect_graph() + +b.write_graph_to_file(f"{96*3}_regular.edges") + +g = nx.read_edgelist(f"{96*3}_regular.edges") +nx.draw(g) +#plt.savefig("96_star.png") diff --git a/random files/ip_addr_1Machines.json b/random files/ip_addr_1Machines.json new file mode 100644 index 0000000000000000000000000000000000000000..15d6591df53574707ac03627fa19c9ecd749b1e3 --- /dev/null +++ b/random files/ip_addr_1Machines.json @@ -0,0 +1,3 @@ +{ + "0": "127.0.0.1" +} \ No newline at end of file diff --git a/random files/learningrate-Copy2.ipynb b/random files/learningrate-Copy2.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..6a5dff362073514bfe9ce3e1c18bad8f0a11bb17 --- /dev/null +++ b/random files/learningrate-Copy2.ipynb @@ -0,0 +1,7121 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZMZYcW3itMzT", + "outputId": "f2970f7e-cf26-4a67-e8d3-29bcd1a11775" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2VftlLfttdT8", + "outputId": "48b47fdc-853b-4711-ae95-8c0e64510615" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "ft7BMl1LyWP6" + }, + "outputs": [], + "source": [ + "from torch import nn\n", + "import torch\n", + "import os\n", + "import json\n", + "import pickle\n", + "import numpy as np\n", + "import pywt\n", + "#from torchvision.models.resnet import ResNet, BasicBlock, Bottleneck\n", + "train_dir = \"../../\"\n", + "my_train_data = {\"x\": [], \"y\": []}" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<torch._C.Generator at 0x7f1e10694c30>" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.manual_seed(13)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "hi0N5rB5xBWn" + }, + "outputs": [], + "source": [ + "if torch.cuda.is_available():\n", + " device = \"cuda\"\n", + "else:\n", + " device = \"cpu\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "6lO3uYsmxNYz", + "outputId": "b170b610-f21e-465d-fcd6-b7e6989e73e5" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'cpu'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "device" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "torch.set_num_threads(6)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Contents\n", + "* [CNN Model Training](#train)\n", + "* [Optimizer analysis](#optim)\n", + "* [FFT](#fft)\n", + "* [Wavelets](#wt)\n", + "* [FFT Training](#ffttrain)\n", + "* [Node_Training](#nodetraining)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CNN Model Training <a class=\"anchor\" id=\"train\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "9LpgzEw1s-xo" + }, + "outputs": [], + "source": [ + "# From Femnist.py\n", + "def read_file(file_path):\n", + " with open(file_path, \"r\") as inf:\n", + " client_data = json.load(inf)\n", + " print(\"loaded the data\")\n", + " return (\n", + " client_data[\"users\"],\n", + " client_data[\"num_samples\"],\n", + " client_data[\"user_data\"],\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QBu1kiw8s-xr" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "raw", + "metadata": { + "id": "jI3ixEN4s-xt", + "outputId": "ed969663-9e1e-4810-9507-52cdc426650a" + }, + "source": [ + "# From Femnist.py\n", + "for i in range(1):\n", + " cur_file = \"leaf/data/femnist/data/train/all_data_0_niid_0_keep_0_train_9.json\"\n", + " # test_file = \"leaf/data/femnist/data/test/all_data_0_niid_0_keep_0_test_9.json\"\n", + " # cur_file = test_file\n", + " clients, _, train_data = read_file(\n", + " os.path.join(train_dir, cur_file)\n", + " )\n", + " for cur_client in clients:\n", + " # self.clients.append(cur_client)\n", + " my_train_data[\"x\"].extend(train_data[cur_client][\"x\"])\n", + " my_train_data[\"y\"].extend(train_data[cur_client][\"y\"])\n", + " del train_data[cur_client]\n" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "wvHsSz8as-xw" + }, + "source": [ + "train_x = (\n", + " np.array(my_train_data[\"x\"], dtype=np.dtype(\"float32\"))\n", + " .reshape(-1, 28, 28, 1)\n", + " .transpose(0, 3, 1, 2)\n", + ")\n", + "train_y = np.array(my_train_data[\"y\"], dtype=np.dtype(\"int64\")).reshape(-1)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "K8X471SKs-xz", + "outputId": "cdf73c06-1323-4e76-850b-16324008d255" + }, + "source": [ + "len(train_y)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "EpWNELBrs-x0" + }, + "source": [ + "with open(train_dir+\"femnist.pkl\", \"wb\") as f:\n", + " pickle.dump({\"test_x\": train_x, \"test_y\": train_y}, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mAEASHr2s-x1" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "Am_XlcSSs-x3" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "evAd9ZvYs-x6" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "9_vIFakbs-x7", + "outputId": "3a8b546a-186f-4519-8c0b-e853986a8101" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856, 1, 28, 28)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_x\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):\n", + " \"\"\"3x3 convolution with padding\"\"\"\n", + " return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,\n", + " padding=dilation, groups=groups, bias=False, dilation=dilation)\n", + "\n", + "\n", + "def conv1x1(in_planes, out_planes, stride=1):\n", + " \"\"\"1x1 convolution\"\"\"\n", + " return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)\n", + "\n", + "class BasicBlock(nn.Module):\n", + " expansion = 1\n", + "\n", + " def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,\n", + " base_width=64, dilation=1, norm_layer=None):\n", + " super(BasicBlock, self).__init__()\n", + " if norm_layer is None:\n", + " norm_layer = nn.BatchNorm2d\n", + " if dilation > 1:\n", + " raise NotImplementedError(\"Dilation > 1 not supported in BasicBlock\")\n", + " # Both self.conv1 and self.downsample layers downsample the input when stride != 1\n", + " self.conv1 = conv3x3(inplanes, planes, stride)\n", + " self.bn1 = norm_layer(planes)\n", + " self.relu = nn.ReLU(inplace=True)\n", + " self.conv2 = conv3x3(planes, planes)\n", + " self.bn2 = norm_layer(planes)\n", + " self.downsample = downsample\n", + " self.stride = stride\n", + " \n", + " def forward(self, x):\n", + " identity = x\n", + "\n", + " out = self.conv1(x)\n", + " out = self.bn1(out)\n", + " out = self.relu(out)\n", + "\n", + " out = self.conv2(out)\n", + " out = self.bn2(out)\n", + "\n", + " if self.downsample is not None:\n", + " identity = self.downsample(x)\n", + "\n", + " out += identity\n", + " out = self.relu(out)\n", + "\n", + " return out\n", + "\n", + "class Bottleneck(nn.Module):\n", + " # Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)\n", + " # while original implementation places the stride at the first 1x1 convolution(self.conv1)\n", + " # according to \"Deep residual learning for image recognition\"https://arxiv.org/abs/1512.03385.\n", + " # This variant is also known as ResNet V1.5 and improves accuracy according to\n", + " # https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.\n", + "\n", + " expansion = 4\n", + "\n", + " def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,\n", + " base_width=64, dilation=1, norm_layer=None):\n", + " super(Bottleneck, self).__init__()\n", + " if norm_layer is None:\n", + " norm_layer = nn.BatchNorm2d\n", + " width = int(planes * (base_width / 64.)) * groups\n", + " # Both self.conv2 and self.downsample layers downsample the input when stride != 1\n", + " self.conv1 = conv1x1(inplanes, width)\n", + " self.bn1 = norm_layer(width)\n", + " self.conv2 = conv3x3(width, width, stride, groups, dilation)\n", + " self.bn2 = norm_layer(width)\n", + " self.conv3 = conv1x1(width, planes * self.expansion)\n", + " self.bn3 = norm_layer(planes * self.expansion)\n", + " self.relu = nn.ReLU(inplace=True)\n", + " self.downsample = downsample\n", + " self.stride = stride\n", + "\n", + " def forward(self, x):\n", + " identity = x\n", + "\n", + " out = self.conv1(x)\n", + " out = self.bn1(out)\n", + " out = self.relu(out)\n", + "\n", + " out = self.conv2(out)\n", + " out = self.bn2(out)\n", + " out = self.relu(out)\n", + "\n", + " out = self.conv3(out)\n", + " out = self.bn3(out)\n", + "\n", + " if self.downsample is not None:\n", + " identity = self.downsample(x)\n", + "\n", + " out += identity\n", + " out = self.relu(out)\n", + "\n", + " return out\n", + "\n", + "class ResNet(nn.Module):\n", + "\n", + " def __init__(self, block, layers, num_classes=1000, zero_init_residual=False,\n", + " groups=1, width_per_group=64, replace_stride_with_dilation=None,\n", + " norm_layer=None):\n", + " super(ResNet, self).__init__()\n", + " if norm_layer is None:\n", + " norm_layer = nn.BatchNorm2d\n", + " self._norm_layer = norm_layer\n", + "\n", + " self.inplanes = 32\n", + " self.dilation = 1\n", + " if replace_stride_with_dilation is None:\n", + " # each element in the tuple indicates if we should replace\n", + " # the 2x2 stride with a dilated convolution instead\n", + " replace_stride_with_dilation = [False, False, False]\n", + " if len(replace_stride_with_dilation) != 3:\n", + " raise ValueError(\"replace_stride_with_dilation should be None \"\n", + " \"or a 3-element tuple, got {}\".format(replace_stride_with_dilation))\n", + " self.groups = groups\n", + " self.base_width = width_per_group\n", + " self.conv1 = nn.Conv2d(1, self.inplanes, kernel_size=7, stride=2, padding=3,\n", + " bias=False)\n", + " self.bn1 = norm_layer(self.inplanes)\n", + " self.relu = nn.ReLU(inplace=True)\n", + " self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)\n", + " self.layer1 = self._make_layer(block, 32, layers[0])\n", + " self.layer2 = self._make_layer(block, 64, layers[1], stride=2,\n", + " dilate=replace_stride_with_dilation[0])\n", + " self.layer3 = self._make_layer(block, 128, layers[2], stride=2,\n", + " dilate=replace_stride_with_dilation[1])\n", + " self.layer4 = self._make_layer(block, 256, layers[3], stride=2,\n", + " dilate=replace_stride_with_dilation[2])\n", + " self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n", + " self.fc = nn.Linear(256 * block.expansion, num_classes)\n", + "\n", + " for m in self.modules():\n", + " if isinstance(m, nn.Conv2d):\n", + " nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')\n", + " elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):\n", + " nn.init.constant_(m.weight, 1)\n", + " nn.init.constant_(m.bias, 0)\n", + "\n", + " # Zero-initialize the last BN in each residual branch,\n", + " # so that the residual branch starts with zeros, and each residual block behaves like an identity.\n", + " # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677\n", + " if zero_init_residual:\n", + " for m in self.modules():\n", + " if isinstance(m, Bottleneck):\n", + " nn.init.constant_(m.bn3.weight, 0)\n", + " elif isinstance(m, BasicBlock):\n", + " nn.init.constant_(m.bn2.weight, 0)\n", + "\n", + " def _make_layer(self, block, planes, blocks, stride=1, dilate=False):\n", + " norm_layer = self._norm_layer\n", + " downsample = None\n", + " previous_dilation = self.dilation\n", + " if dilate:\n", + " self.dilation *= stride\n", + " stride = 1\n", + " if stride != 1 or self.inplanes != planes * block.expansion:\n", + " downsample = nn.Sequential(\n", + " conv1x1(self.inplanes, planes * block.expansion, stride),\n", + " norm_layer(planes * block.expansion),\n", + " )\n", + "\n", + " layers = []\n", + " layers.append(block(self.inplanes, planes, stride, downsample, self.groups,\n", + " self.base_width, previous_dilation, norm_layer))\n", + " self.inplanes = planes * block.expansion\n", + " for _ in range(1, blocks):\n", + " layers.append(block(self.inplanes, planes, groups=self.groups,\n", + " base_width=self.base_width, dilation=self.dilation,\n", + " norm_layer=norm_layer))\n", + "\n", + " return nn.Sequential(*layers)\n", + "\n", + " def _forward_impl(self, x):\n", + " # See note [TorchScript super()]\n", + " x = self.conv1(x)\n", + " x = self.bn1(x)\n", + " x = self.relu(x)\n", + " x = self.maxpool(x)\n", + "\n", + " x = self.layer1(x)\n", + " x = self.layer2(x)\n", + " x = self.layer3(x)\n", + " x = self.layer4(x)\n", + "\n", + " x = self.avgpool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.fc(x)\n", + "\n", + " return x\n", + "\n", + " def forward(self, x):\n", + " return self._forward_impl(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "GPyZ2C8ws-x9" + }, + "outputs": [], + "source": [ + "NUM_CLASSES = 62\n", + "IMAGE_SIZE = (28, 28)\n", + "FLAT_SIZE = 28 * 28\n", + "PIXEL_RANGE = 256.0\n", + "\n", + "model = ResNet(BasicBlock, [2,2,2,2], num_classes=62, width_per_group=32)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "bCgW8ClBs-x_" + }, + "outputs": [], + "source": [ + "flat = []\n", + "for v in model.state_dict().values():\n", + " flat.append(v.flatten())\n", + "conc = torch.cat(flat)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([2816498])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "conc.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "oBGwcwZks-yA" + }, + "outputs": [], + "source": [ + "import os\n", + "from torch.utils.data import Dataset\n", + "\n", + "class FemnistDataset(Dataset):\n", + " def __init__(self, training, transform=None, target_transform=None):\n", + " if training:\n", + " with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)\n", + " self.data = train[\"train_x\"]\n", + " self.label = train[\"train_y\"]\n", + " else: \n", + " with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)\n", + " self.data = test[\"test_x\"]\n", + " self.label = test[\"test_y\"]\n", + " self.transform = transform\n", + " self.target_transform = target_transform\n", + "\n", + " def __len__(self):\n", + " return len(self.label)\n", + "\n", + " def __getitem__(self, idx):\n", + " return self.data[idx], self.label[idx]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "U3boC_N4s-yC" + }, + "outputs": [], + "source": [ + "from torch.utils.data import DataLoader" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "id": "sJsrQXkEs-yD" + }, + "outputs": [], + "source": [ + "trainset = FemnistDataset(True)\n", + "testset = FemnistDataset(False)\n", + "\n", + "train_dataloader = DataLoader(trainset, batch_size=128, shuffle=True)\n", + "test_dataloader = DataLoader(testset, batch_size=128, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "id": "e65Izyv0s-yE" + }, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = model.to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,\n", + " 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "for v in model.state_dict().values():\n", + " flat.append(v.flatten())\n", + "conc = torch.cat(flat)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([-3.6153e-02, 1.0922e-02, 1.5911e-01, 7.6926e-02, 5.7525e-02,\n", + " 2.0833e-01, 4.8255e-02, 2.0805e-01, -2.4887e-02, 8.3241e-02,\n", + " 5.7281e-02, 3.2598e-02, -5.9614e-03, 2.3448e-01, -2.7755e-02,\n", + " 1.2072e-01, 2.0834e-03, 1.4729e-01, -2.0169e-01, -2.3126e-03,\n", + " -1.0632e-02, 1.1928e-02, -1.2216e-01, -1.3769e-03, -1.1989e-01,\n", + " -2.1655e-02, 1.6833e-02, -1.0780e-01, 5.3008e-02, 1.1340e-01,\n", + " -1.1262e-01, -2.9909e-02, -1.3595e-01, 1.1996e-01, -3.5497e-02,\n", + " -5.9646e-02, -8.5283e-03, -3.5111e-02, -7.9876e-03, 4.3423e-02,\n", + " 8.0446e-02, 1.3475e-01, -1.7352e-02, 1.5214e-01, 5.7564e-02,\n", + " -1.2092e-02, 4.2873e-02, -4.6847e-02, -1.5831e-01, 3.2632e-02,\n", + " 1.2103e-02, -7.3686e-02, 5.8829e-02, -4.9315e-02, 1.1395e-02,\n", + " -1.2393e-02, 3.4627e-02, -2.0724e-02, -7.6100e-02, 1.5033e-02,\n", + " -6.2240e-02, 1.3045e-01, 2.9429e-02, 5.1437e-02, 5.2329e-02,\n", + " 2.4896e-02, -1.8821e-02, -4.8809e-02, -6.7213e-02, -1.0350e-02,\n", + " -9.7824e-03, 8.3952e-02, 7.2283e-02, -6.4382e-02, 1.5534e-01,\n", + " 8.4570e-02, -1.6595e-01, 4.1408e-03, 4.5516e-02, -5.6906e-02,\n", + " -4.2940e-02, -1.1772e-02, -5.6404e-02, 1.8210e-01, 2.0227e-02,\n", + " 7.7609e-02, -1.4693e-01, -6.8822e-02, -3.4503e-02, 4.1717e-02,\n", + " 6.6086e-02, 1.1133e-01, 1.3154e-02, -3.4234e-02, 9.1784e-04,\n", + " -2.9296e-02, 2.6286e-02, -1.1241e-01, -8.3519e-02, 1.9695e-01,\n", + " -9.7168e-02, -5.8979e-02, 1.5797e-02, 3.9749e-02, 3.8752e-02,\n", + " -7.1771e-02, -7.8542e-02, -1.0243e-02, 1.7219e-01, -1.1095e-01,\n", + " 1.2735e-01, -4.5902e-02, -9.4965e-03, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00, 1.0000e+00,\n", + " 1.0000e+00, 0.0000e+00, 1.6987e-01, -1.2518e-02, 7.4222e-02,\n", + " 8.1779e-04, 1.0769e-01, 1.7932e-01, 1.0626e-01, 5.5261e-02,\n", + " -7.1285e-02, 3.4232e-02, -1.9942e-01, -3.2020e-02, -5.8090e-04,\n", + " -3.1324e-03, -5.2624e-02, -1.1991e-01, -6.3235e-02, -5.6224e-02,\n", + " -3.8221e-03, 1.7819e-02, 1.5929e-01, -1.2379e-01, -1.1942e-01,\n", + " -9.9741e-02, 3.7306e-02, -4.5313e-02, 9.5044e-02, -1.0798e-01,\n", + " 4.7692e-02, -6.8353e-02, -6.4735e-02, 1.6302e-01, -7.3956e-02,\n", + " -5.7375e-02, -7.0186e-02, -1.9878e-02, 6.8199e-02, -7.7473e-02,\n", + " 1.1649e-01, -1.7948e-01, 6.5320e-02, -1.6462e-01, -1.7468e-01,\n", + " 6.9575e-02, -3.6026e-02, -1.8932e-02, 3.2033e-02, 3.8191e-02,\n", + " 4.2004e-02, 9.8125e-03, -2.4546e-02, 8.1653e-03, -4.7182e-02,\n", + " -1.4758e-01, 3.9359e-02, -2.0074e-02, 5.3813e-02, 1.3991e-02,\n", + " -3.9933e-02, -9.2483e-02, -6.1893e-02, 2.6557e-03, 1.9068e-02,\n", + " 4.8750e-02, 6.6708e-02, 1.9469e-02, -2.1096e-02, 4.4306e-02,\n", + " -9.8441e-02, 3.5618e-03, -7.8726e-02, 9.7077e-02, -2.4202e-02,\n", + " 1.7504e-02, 1.4211e-01, 6.3227e-02, 2.9580e-03, -2.3347e-02,\n", + " 5.8336e-02, -5.9110e-02, 7.2662e-02, 5.8302e-02, -6.3689e-02,\n", + " -1.7816e-02, -1.3492e-01, 1.1300e-01, -3.2642e-02, -4.5522e-02,\n", + " -8.7756e-02, 2.1591e-02, 1.7699e-01, 1.1176e-02, -4.9630e-02,\n", + " -1.1987e-01, 8.9175e-02, -1.5066e-02, -1.0060e-02, -3.6194e-03,\n", + " 6.5334e-02, 7.3754e-02, 1.2938e-02, -3.8157e-02, 4.3455e-02,\n", + " 2.0767e-02, 6.2418e-02, -3.1317e-03, -6.5233e-03, -2.9303e-02,\n", + " 5.8986e-02, 3.9827e-02, -4.4528e-02, 3.3096e-02, 1.4558e-01,\n", + " -7.1790e-02, 2.8021e-02, -1.1121e-01, -8.7729e-02, -1.6679e-02,\n", + " 6.0385e-02, -1.0069e-01, 3.8162e-03, -1.5804e-02, 9.3877e-03,\n", + " -1.9549e-02, 6.8907e-02, 9.2226e-02, 6.7532e-02, 5.1782e-02,\n", + " -5.0173e-02, 6.4691e-02, 5.3740e-03, 2.6782e-02, 1.7140e-01,\n", + " -7.1114e-02, 1.3247e-01, 1.9341e-02, -2.8109e-02, -9.6079e-02,\n", + " -1.6598e-01, 1.1776e-01, -1.2546e-01, 8.9671e-02, -1.1108e-01,\n", + " 4.8116e-03, 1.5545e-02, 1.0199e-01, -9.5309e-02, -1.4364e-03,\n", + " -4.8351e-02, -8.6616e-02, 2.2615e-02, -5.3860e-02, -4.1553e-02,\n", + " -3.7117e-02, -1.3335e-01, 6.1934e-02, -6.1574e-03, -4.8353e-04,\n", + " -6.7036e-02, 9.5313e-03, 6.4967e-02, 1.0548e-01, -8.5173e-02,\n", + " 1.6937e-02, 1.8506e-01, 1.1589e-01, 1.5855e-02, 5.2601e-02,\n", + " -1.9648e-02, -2.8683e-02, 1.7219e-02, 4.4335e-02, -1.2565e-01,\n", + " -1.1790e-01, 2.4435e-04, 1.0657e-01, 4.9675e-02, -1.5611e-02,\n", + " -1.0195e-02, -2.6327e-02, 6.7269e-02, -2.0982e-02, 1.9502e-03,\n", + " -1.5793e-02, 2.6358e-02, 6.0283e-02, 1.3618e-01, 1.3374e-01,\n", + " -2.5466e-02, -4.8720e-02, -1.8593e-01, 1.7561e-03, -1.2250e-01,\n", + " -1.6137e-01, -5.0002e-03, -1.2871e-01, -3.7437e-02, -4.0313e-02,\n", + " 3.4365e-02, -3.7071e-02, 2.2959e-02, 1.1128e-01, -4.9545e-03,\n", + " -2.6472e-02, 3.2626e-02, -1.7230e-02, 7.8508e-02, 2.7197e-02,\n", + " -9.8706e-02, 1.1325e-02, -4.3507e-02, 3.5809e-02, -8.2735e-02,\n", + " -3.1467e-02, -2.3812e-03, 2.2783e-01, 1.4469e-01, 4.7378e-02,\n", + " 1.1900e-01, 1.3966e-02, -1.5898e-01, -5.6670e-02, 6.0425e-02,\n", + " 4.4461e-02, 4.3565e-02, -1.3006e-01, -3.5693e-02, -1.6811e-02,\n", + " 7.3669e-02, -5.5727e-03, 2.3922e-02, -1.0258e-01, -2.0600e-02,\n", + " 7.0644e-02, 5.4080e-02, -1.8225e-02, 8.2288e-02, 1.3712e-01,\n", + " 9.1076e-03, -5.9369e-02, -1.2339e-01, -9.4833e-02, 3.3790e-02,\n", + " 2.7712e-02, 1.1237e-01, 9.4319e-02, 6.9273e-03, 2.7316e-02,\n", + " -2.6998e-02, 6.5125e-02, 3.9116e-02, -1.7837e-02, -7.1617e-02,\n", + " 4.7388e-02, 6.2827e-02, 8.7470e-02, -1.4028e-02, 3.4789e-02,\n", + " -1.0830e-01, 2.5725e-03, 7.5497e-02, -5.1828e-02, 2.0584e-01,\n", + " -2.0988e-02, 1.3311e-01, 1.8669e-02, -1.0620e-01, 6.3515e-02,\n", + " 2.3155e-02, 5.2781e-02, 9.0113e-02, -1.6853e-01, 3.3725e-02,\n", + " -8.8361e-02, 9.8612e-02, -7.9768e-02, 2.4839e-02, 5.0955e-02,\n", + " 1.9578e-01, 4.9857e-02, -4.9117e-02, -6.0971e-02, -7.1335e-02,\n", + " 4.8186e-03, 2.6048e-01, -4.1628e-02, 6.4097e-02, -6.2915e-02,\n", + " -2.2990e-02, -1.0170e-01, 7.9752e-02, 1.4351e-01, -5.9676e-02,\n", + " 1.0420e-02, -2.1729e-02, 3.7526e-02, -3.2499e-02, 7.3554e-02,\n", + " -1.1204e-01, -7.0101e-02, -1.3232e-01, -8.4415e-02, -7.2395e-02,\n", + " 1.0182e-01, -3.3702e-03, 5.1951e-02, 5.0360e-02, -7.8748e-02,\n", + " 7.5663e-02, 8.7619e-02, 5.2736e-02, 1.0218e-01, 1.5727e-02,\n", + " -3.0746e-02, 5.0295e-02, 5.2703e-03, 5.5152e-02, -9.1586e-02,\n", + " -2.4175e-02, -8.0762e-03, -9.6645e-02, 5.7554e-02, 3.0361e-02,\n", + " 5.6569e-02, 1.1550e-01, -8.5696e-02, -1.2037e-01, 1.4408e-01,\n", + " -6.9288e-02, -9.6466e-02, -1.0642e-01, 6.7118e-02, -4.6111e-02,\n", + " 1.2625e-01, -2.2200e-02, 1.8784e-01, 5.6559e-02, -9.2792e-03,\n", + " 1.0988e-01, -8.4376e-02, 2.0674e-02, 5.1443e-02, -6.3788e-02,\n", + " 9.2447e-02, 5.4876e-03, -5.5736e-02, 1.1064e-01, -9.2663e-02,\n", + " -1.3774e-02, -1.1738e-02, 1.1746e-01, -1.1146e-01, 5.0254e-02,\n", + " -2.7132e-02, 6.3535e-02, -5.7441e-02, 1.4019e-01, 1.5358e-01,\n", + " -9.0577e-02, -6.1400e-02, -8.2789e-03, -3.0574e-02, -1.6684e-01,\n", + " 2.1997e-02, 1.2047e-01, -8.1132e-02, 2.7643e-02, -4.1913e-02,\n", + " 7.8445e-02, 3.4260e-02, 1.9198e-02, 8.3587e-03, 8.4882e-02,\n", + " 4.7922e-02, 3.2085e-03, 6.3019e-02, -1.2356e-01, -2.2035e-02,\n", + " -1.4141e-01, 3.0651e-02, -4.9958e-02, 2.0171e-02, -1.0585e-01,\n", + " -1.4497e-01, -4.1225e-02, -6.8969e-02, -1.5650e-01, -8.4516e-02,\n", + " -7.2454e-02, -1.9754e-02, -2.0815e-02, -1.4435e-01, -1.3507e-01,\n", + " -9.3353e-03, -7.8647e-02, 4.9376e-02, -9.1362e-02, -2.6405e-04,\n", + " -1.1060e-01, 6.1339e-02, -1.6488e-01, -1.2586e-02, -1.6126e-01,\n", + " -5.5025e-02, -3.0095e-02, -6.0076e-02, -8.4154e-02, -4.5846e-02,\n", + " 1.0521e-01, -1.0573e-01, -5.6448e-03, -1.1787e-01, -1.6642e-01,\n", + " -4.6485e-02, 2.1018e-03, -1.7721e-01, -2.3989e-02, 2.2526e-03,\n", + " -3.3936e-02, -8.5082e-04, 2.3318e-02, -1.2200e-01, -3.8985e-02,\n", + " -5.0310e-02, -2.1276e-01, -1.0934e-01, 5.0431e-02, 1.5243e-01,\n", + " -4.5213e-02, 5.6250e-02, -5.1513e-02, -7.0380e-02, 1.3558e-02,\n", + " 4.8311e-02, -1.0758e-01, -6.9672e-02, 4.1720e-02, -3.7519e-02,\n", + " 4.4889e-03, 3.1567e-02, 1.8889e-01, -2.1389e-02, -1.7544e-01,\n", + " 4.2167e-02, 2.3926e-01, -8.3352e-02, 2.3343e-02, 1.1568e-01,\n", + " -4.0584e-02, 4.9951e-02, 3.1471e-02, 5.3396e-02, 4.5164e-02,\n", + " 9.5883e-02, -1.0847e-01, -1.0457e-01, 4.1262e-02, 6.4844e-02,\n", + " 9.8069e-02, 1.5135e-02, -2.5175e-02, 7.6218e-02, -6.0823e-02,\n", + " -1.1629e-01, 6.7468e-03, 2.0872e-02, 1.2584e-01, -3.4727e-02,\n", + " -1.0161e-01, 8.7080e-02, -2.7376e-04, -4.8307e-02, -1.0124e-01,\n", + " -7.6946e-02, -1.9775e-02, -4.2434e-02, 3.4611e-02, 7.3197e-02,\n", + " 1.0860e-02, -1.0779e-02, -1.1027e-01, -2.7294e-02, 2.2437e-02,\n", + " -1.6622e-01, -2.6583e-02, 5.8286e-02, 2.9824e-03, -5.5497e-02,\n", + " 5.0274e-02, 5.9907e-02, 1.5858e-01, -2.4947e-02, 7.6584e-02,\n", + " 8.5319e-02, 3.4722e-03, 1.0288e-01, 1.0969e-01, 6.5799e-02,\n", + " -2.6551e-02, -1.7372e-01, 1.4605e-01, 2.1898e-02, -3.5002e-03,\n", + " -1.5310e-01, -3.0351e-02, 5.7421e-02, -1.3553e-01, -9.7861e-02,\n", + " 1.3477e-01, -1.2629e-01, -8.7702e-02, -4.4454e-03, -7.2945e-03,\n", + " -7.9274e-02, -1.0867e-02, 3.8146e-02, 1.0687e-01, -2.5816e-03,\n", + " 1.6793e-02, 6.4059e-02, -7.5229e-02, -8.1442e-02, 8.3586e-03,\n", + " -8.0715e-02, 8.9084e-03, -1.0933e-01, -1.4269e-02, -7.3607e-03,\n", + " 1.5704e-02, 9.4702e-03, 2.2811e-02, -8.7653e-02, 9.0603e-02,\n", + " 6.9251e-02, -3.1635e-02, 9.3687e-03, 5.9566e-03, -1.1568e-02,\n", + " 7.7497e-02, 8.1724e-03, 7.5156e-02, 5.9760e-02, -9.0665e-02,\n", + " -4.1795e-02, -5.5084e-02, -2.1276e-02, -7.5714e-03, 8.1334e-02,\n", + " 3.2634e-02, -6.9134e-02, 7.7450e-02, -6.0068e-02, 1.4064e-01,\n", + " -1.5251e-01, -5.5206e-02, 9.4398e-02, 6.7102e-02, -2.1777e-02,\n", + " -1.0860e-01, 8.1245e-02, -7.5645e-02, 1.3485e-02, 8.9177e-02,\n", + " 1.7675e-02, -8.5894e-02, -1.2788e-02, 2.8444e-02, 1.0189e-01,\n", + " 1.3065e-01, 4.1666e-02, 4.3118e-02, -4.6221e-03, -8.9139e-02,\n", + " 7.8242e-02, 6.2911e-02, -2.1091e-01, -8.0931e-02, 3.9291e-02,\n", + " 2.0712e-01, -1.2777e-02, 3.2420e-02, 3.9909e-02, -4.8477e-02,\n", + " 1.1958e-01, -6.7129e-02, -5.5796e-02, -7.8439e-02, 1.0222e-01,\n", + " -1.2084e-01, 5.1758e-02, 1.8989e-01, -2.1552e-01, 1.0309e-01,\n", + " 1.4989e-01, 2.9901e-02, 5.6023e-02, -7.9886e-03, 4.2809e-02,\n", + " 7.0390e-02, 6.5856e-02, 1.8404e-02, -1.8389e-01, 3.2689e-02,\n", + " -2.9534e-02, -7.4516e-02, 1.9053e-02, 6.8197e-03, -8.6406e-02,\n", + " -1.2057e-01, 5.4083e-02, -2.8486e-02, 2.0098e-03, -2.4764e-02,\n", + " -6.8012e-02, -9.7861e-02, 2.7055e-02, 3.1677e-02, 1.7974e-02,\n", + " 5.6053e-02, -1.2744e-02, 1.1241e-02, 1.1206e-01, -3.9609e-02,\n", + " 1.8022e-02, -3.5299e-02, 4.1814e-02, -7.1772e-02, -7.2119e-02,\n", + " 3.1803e-02, -5.6058e-02, -1.2408e-01, 1.1487e-01, 8.2424e-02,\n", + " -7.6738e-02, 3.6102e-02, 1.0330e-01, 1.6182e-01, 7.3596e-02,\n", + " -8.2679e-02, 2.3563e-02, -4.7735e-02, 5.1281e-02, -4.4526e-02,\n", + " -1.8515e-02, 1.0371e-02, -2.1650e-02, 1.7475e-02, -6.6999e-02,\n", + " -3.5237e-03, -6.6710e-03, 4.5694e-02, -2.4330e-02, -9.4324e-02,\n", + " 1.0351e-01, -9.7201e-02, 9.9928e-02, 6.0018e-03, -1.9398e-01,\n", + " -6.9612e-02, 3.7000e-02, 2.5857e-02, -2.0493e-01, 1.0143e-01,\n", + " 2.9652e-02, -1.0923e-01, -1.3063e-01, 8.0357e-02, -2.8222e-02,\n", + " 1.1236e-01, 1.0068e-01, 1.8715e-01, -4.7519e-03, -1.9877e-02,\n", + " -5.8805e-02, -2.2623e-02, -9.1535e-02, -3.9104e-02, 1.1634e-02,\n", + " -1.2658e-02, -1.9400e-01, 1.3103e-01, 3.6966e-02, -6.6630e-02,\n", + " 3.6699e-02, -1.3168e-01, -3.5448e-02, -6.5795e-02, 3.8508e-02,\n", + " -2.8908e-02, 5.9616e-03, -1.1947e-01, -4.5128e-02, 2.2609e-02,\n", + " -6.0078e-02, 1.2044e-02, -4.2161e-02, -1.7942e-01, -1.4760e-01,\n", + " -2.2213e-02, -1.2489e-01, 1.2302e-01, 2.6101e-02, 1.1545e-01,\n", + " -6.0973e-02, -9.3216e-02, -1.3401e-01, 6.9192e-02, 1.0547e-01,\n", + " 4.1468e-02, 7.5163e-02, -4.5361e-02, 2.8214e-02, -9.8323e-02,\n", + " -8.9710e-04, 7.1415e-02, -8.6964e-02, 7.2207e-02, -5.4545e-02,\n", + " -4.4864e-02, -1.0401e-02, 1.1054e-02, -5.4850e-03, -1.5119e-01,\n", + " 2.7383e-02, 7.9438e-02, 9.7938e-02, -7.6253e-02, -9.8225e-02,\n", + " -3.6008e-03, 2.5735e-02, -4.4595e-02, 9.2904e-03, 2.4263e-02,\n", + " -1.1514e-02, -2.5885e-02, 9.3242e-02, 3.7527e-02, 1.4858e-03,\n", + " 4.4235e-02, 4.6888e-02, 2.9045e-04, -3.7129e-02, -1.3034e-01,\n", + " -1.3929e-01, 6.9240e-02, -2.5642e-02, -8.9732e-03, -1.2048e-01,\n", + " 5.1459e-02, -5.1739e-02, -8.8432e-02, -6.8968e-02, -1.3449e-01,\n", + " 1.8770e-02, 1.4933e-01, -1.4537e-01, -1.3368e-02, -2.0281e-03])\n" + ] + } + ], + "source": [ + "o = 10800\n", + "print(conc[o:o+1000])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "eqOXilqMs-yF", + "outputId": "06799a3b-983b-4f51-a7bd-a901c041bd05" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.317379 [ 0/735856]\n", + "loss: 1.467329 [12800/735856]\n", + "loss: 0.863656 [25600/735856]\n", + "loss: 0.814204 [38400/735856]\n", + "loss: 0.746839 [51200/735856]\n", + "loss: 0.734121 [64000/735856]\n", + "loss: 0.761491 [76800/735856]\n", + "loss: 0.680998 [89600/735856]\n", + "loss: 0.731149 [102400/735856]\n", + "loss: 0.826501 [115200/735856]\n", + "loss: 0.662327 [128000/735856]\n", + "loss: 0.612664 [140800/735856]\n", + "loss: 0.755015 [153600/735856]\n", + "loss: 0.400373 [166400/735856]\n", + "loss: 0.558040 [179200/735856]\n", + "loss: 0.603362 [192000/735856]\n", + "loss: 0.418064 [204800/735856]\n", + "loss: 0.628256 [217600/735856]\n", + "loss: 0.377127 [230400/735856]\n", + "loss: 0.420045 [243200/735856]\n", + "loss: 0.558597 [256000/735856]\n", + "loss: 0.438556 [268800/735856]\n", + "loss: 0.684690 [281600/735856]\n", + "loss: 0.590059 [294400/735856]\n", + "loss: 0.557874 [307200/735856]\n", + "loss: 0.494909 [320000/735856]\n", + "loss: 0.617219 [332800/735856]\n", + "loss: 0.351243 [345600/735856]\n", + "loss: 0.454522 [358400/735856]\n", + "loss: 0.429664 [371200/735856]\n", + "loss: 0.468215 [384000/735856]\n", + "loss: 0.401258 [396800/735856]\n", + "loss: 0.474102 [409600/735856]\n", + "loss: 0.562686 [422400/735856]\n", + "loss: 0.483383 [435200/735856]\n", + "loss: 0.348151 [448000/735856]\n", + "loss: 0.528455 [460800/735856]\n", + "loss: 0.545382 [473600/735856]\n", + "loss: 0.370390 [486400/735856]\n", + "loss: 0.567488 [499200/735856]\n", + "loss: 0.480258 [512000/735856]\n", + "loss: 0.605147 [524800/735856]\n", + "loss: 0.415480 [537600/735856]\n", + "loss: 0.427186 [550400/735856]\n", + "loss: 0.391611 [563200/735856]\n", + "loss: 0.604008 [576000/735856]\n", + "loss: 0.745116 [588800/735856]\n", + "loss: 0.357690 [601600/735856]\n", + "loss: 0.347922 [614400/735856]\n", + "loss: 0.518981 [627200/735856]\n", + "loss: 0.435502 [640000/735856]\n", + "loss: 0.387361 [652800/735856]\n", + "loss: 0.449226 [665600/735856]\n", + "loss: 0.447640 [678400/735856]\n", + "loss: 0.403468 [691200/735856]\n", + "loss: 0.349100 [704000/735856]\n", + "loss: 0.361501 [716800/735856]\n", + "loss: 0.315695 [729600/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.0%, Avg loss: 0.434803 \n", + "\n", + "loss: 0.436410 [ 0/735856]\n", + "loss: 0.429430 [12800/735856]\n", + "loss: 0.300599 [25600/735856]\n", + "loss: 0.416907 [38400/735856]\n", + "loss: 0.505084 [51200/735856]\n", + "loss: 0.399249 [64000/735856]\n", + "loss: 0.379393 [76800/735856]\n", + "loss: 0.375960 [89600/735856]\n", + "loss: 0.408403 [102400/735856]\n", + "loss: 0.499817 [115200/735856]\n", + "loss: 0.450748 [128000/735856]\n", + "loss: 0.408854 [140800/735856]\n", + "loss: 0.342387 [153600/735856]\n", + "loss: 0.330833 [166400/735856]\n", + "loss: 0.416435 [179200/735856]\n", + "loss: 0.340663 [192000/735856]\n", + "loss: 0.408621 [204800/735856]\n", + "loss: 0.444404 [217600/735856]\n", + "loss: 0.453196 [230400/735856]\n", + "loss: 0.408210 [243200/735856]\n", + "loss: 0.460274 [256000/735856]\n", + "loss: 0.334112 [268800/735856]\n", + "loss: 0.330720 [281600/735856]\n", + "loss: 0.316345 [294400/735856]\n", + "loss: 0.248728 [307200/735856]\n", + "loss: 0.464760 [320000/735856]\n", + "loss: 0.427282 [332800/735856]\n", + "loss: 0.431015 [345600/735856]\n", + "loss: 0.491930 [358400/735856]\n", + "loss: 0.379011 [371200/735856]\n", + "loss: 0.336299 [384000/735856]\n", + "loss: 0.312829 [396800/735856]\n", + "loss: 0.355771 [409600/735856]\n", + "loss: 0.289162 [422400/735856]\n", + "loss: 0.583171 [435200/735856]\n", + "loss: 0.499083 [448000/735856]\n", + "loss: 0.423254 [460800/735856]\n", + "loss: 0.436303 [473600/735856]\n", + "loss: 0.360267 [486400/735856]\n", + "loss: 0.376950 [499200/735856]\n", + "loss: 0.424678 [512000/735856]\n", + "loss: 0.381343 [524800/735856]\n", + "loss: 0.429872 [537600/735856]\n", + "loss: 0.355957 [550400/735856]\n", + "loss: 0.409392 [563200/735856]\n", + "loss: 0.352608 [576000/735856]\n", + "loss: 0.265125 [588800/735856]\n", + "loss: 0.406446 [601600/735856]\n", + "loss: 0.368569 [614400/735856]\n", + "loss: 0.437190 [627200/735856]\n", + "loss: 0.305703 [640000/735856]\n", + "loss: 0.347399 [652800/735856]\n", + "loss: 0.331695 [665600/735856]\n", + "loss: 0.457639 [678400/735856]\n", + "loss: 0.473799 [691200/735856]\n", + "loss: 0.489939 [704000/735856]\n", + "loss: 0.370199 [716800/735856]\n", + "loss: 0.331481 [729600/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.6%, Avg loss: 0.387414 \n", + "\n", + "loss: 0.443714 [ 0/735856]\n", + "loss: 0.449352 [12800/735856]\n", + "loss: 0.414199 [25600/735856]\n", + "loss: 0.404422 [38400/735856]\n", + "loss: 0.368516 [51200/735856]\n", + "loss: 0.346299 [64000/735856]\n", + "loss: 0.484283 [76800/735856]\n", + "loss: 0.401498 [89600/735856]\n", + "loss: 0.410465 [102400/735856]\n", + "loss: 0.273847 [115200/735856]\n", + "loss: 0.399912 [128000/735856]\n", + "loss: 0.479173 [140800/735856]\n", + "loss: 0.401442 [153600/735856]\n", + "loss: 0.285392 [166400/735856]\n", + "loss: 0.421379 [179200/735856]\n", + "loss: 0.279620 [192000/735856]\n", + "loss: 0.390798 [204800/735856]\n", + "loss: 0.212120 [217600/735856]\n", + "loss: 0.354751 [230400/735856]\n", + "loss: 0.219936 [243200/735856]\n", + "loss: 0.402732 [256000/735856]\n", + "loss: 0.519650 [268800/735856]\n", + "loss: 0.288248 [281600/735856]\n", + "loss: 0.384210 [294400/735856]\n", + "loss: 0.478157 [307200/735856]\n", + "loss: 0.439406 [320000/735856]\n", + "loss: 0.389753 [332800/735856]\n", + "loss: 0.356618 [345600/735856]\n", + "loss: 0.323311 [358400/735856]\n", + "loss: 0.398488 [371200/735856]\n", + "loss: 0.319226 [384000/735856]\n", + "loss: 0.332842 [396800/735856]\n", + "loss: 0.252516 [409600/735856]\n", + "loss: 0.293284 [422400/735856]\n", + "loss: 0.334755 [435200/735856]\n", + "loss: 0.377591 [448000/735856]\n", + "loss: 0.380793 [460800/735856]\n", + "loss: 0.403311 [473600/735856]\n", + "loss: 0.357482 [486400/735856]\n", + "loss: 0.304435 [499200/735856]\n", + "loss: 0.241090 [512000/735856]\n", + "loss: 0.324607 [524800/735856]\n", + "loss: 0.328274 [537600/735856]\n", + "loss: 0.244099 [550400/735856]\n", + "loss: 0.415031 [563200/735856]\n", + "loss: 0.348006 [576000/735856]\n", + "loss: 0.283688 [588800/735856]\n", + "loss: 0.300562 [601600/735856]\n", + "loss: 0.326958 [614400/735856]\n", + "loss: 0.369248 [627200/735856]\n", + "loss: 0.332926 [640000/735856]\n", + "loss: 0.302038 [652800/735856]\n", + "loss: 0.342727 [665600/735856]\n", + "loss: 0.368321 [678400/735856]\n", + "loss: 0.231897 [691200/735856]\n", + "loss: 0.431953 [704000/735856]\n", + "loss: 0.248471 [716800/735856]\n", + "loss: 0.294091 [729600/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.0%, Avg loss: 0.366894 \n", + "\n", + "loss: 0.376553 [ 0/735856]\n", + "loss: 0.220013 [12800/735856]\n", + "loss: 0.282281 [25600/735856]\n", + "loss: 0.397939 [38400/735856]\n", + "loss: 0.286681 [51200/735856]\n", + "loss: 0.299091 [64000/735856]\n", + "loss: 0.373950 [76800/735856]\n", + "loss: 0.429636 [89600/735856]\n", + "loss: 0.306355 [102400/735856]\n", + "loss: 0.411843 [115200/735856]\n", + "loss: 0.228846 [128000/735856]\n", + "loss: 0.207205 [140800/735856]\n", + "loss: 0.351640 [153600/735856]\n", + "loss: 0.401937 [166400/735856]\n", + "loss: 0.273460 [179200/735856]\n", + "loss: 0.327492 [192000/735856]\n", + "loss: 0.331937 [204800/735856]\n", + "loss: 0.228119 [217600/735856]\n", + "loss: 0.287975 [230400/735856]\n", + "loss: 0.224747 [243200/735856]\n", + "loss: 0.283936 [256000/735856]\n", + "loss: 0.342105 [268800/735856]\n", + "loss: 0.292306 [281600/735856]\n", + "loss: 0.292342 [294400/735856]\n", + "loss: 0.240786 [307200/735856]\n", + "loss: 0.313040 [320000/735856]\n", + "loss: 0.419340 [332800/735856]\n", + "loss: 0.489452 [345600/735856]\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(10):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + "\n", + " if batch % 100 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4P-VA0vcs-yH" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"/results:128:\"+str(lr)+\".pkl\", \"wb\") as f:\n", + " pickle.dump(stats, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "641-b_VCvT2b", + "outputId": "cced38ab-5c04-45b2-faf4-e73327126159" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "F_OKqiiHs-yJ", + "outputId": "65786b88-05f4-42fa-a851-03397ef4457a" + }, + "outputs": [], + "source": [ + "lrs = [0.1, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00001]\n", + "for l in lrs:\n", + " with open(train_dir+\"/results:128:\"+str(l)+\".pkl\", \"rb\") as f:\n", + " res = pickle.load(f)\n", + " print(str(l)+\": \" + str(np.amax(res[\"test\"], axis=0)))#+ str(np.max(res[\"test\"]))\n", + " # print(str(l)+\": \" + str(res[\"test\"]))\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rADw-XkfKjOo", + "outputId": "06c54a2c-f7c2-4610-f879-3e1c2f98543f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.1: [[0, 3.6898819485246297, 4.914933837429111], [1, 3.695287103771977, 4.914933837429111], [2, 3.691172517592003, 5.505213732544667], [3, 3.6920483804158226, 4.967376059515824], [4, 3.6939517986755845, 5.505213732544667], [5, 3.6917366434742993, 4.914933837429111], [6, 3.695435837910811, 5.505213732544667], [7, 3.6978058357506574, 5.135679004817367], [8, 3.6948341036363623, 5.505213732544667], [9, 3.6921330658768343, 5.135679004817367]]\n", + "0.01: [[0, 0.5728003431500958, 81.8086468687115], [1, 0.5517885946725348, 82.61967193121532], [2, 3.984756194857093, 25.844258796268065], [3, 0.5739870879932797, 81.7476675407037], [4, 0.7832032613188912, 75.77779132873955], [5, 0.7142617320772638, 77.80474419171901], [6, 0.6602287095348103, 79.28654186230868], [7, 0.6738644539380036, 79.2719068235868], [8, 0.6469118589079138, 79.77071772669065], [9, 0.6788249858734946, 79.28898103542899]]\n", + "0.005: [[0, 0.4834194714537649, 83.79047502896519], [1, 0.466142692822562, 84.33928898103544], [2, 0.4559767278791776, 84.9515214342338], [3, 0.4488265364432298, 84.86493078846271], [4, 0.4554814101660307, 84.773461796451], [5, 0.5149212768315897, 83.05872309287152], [6, 0.4551808235472338, 84.86127202878224], [7, 0.4531376465992325, 85.06494298432831], [8, 0.4589428385362238, 84.83078236477834], [9, 0.4409179601951992, 85.40642722117202]]\n", + "0.001: [[0, 0.4104761779773254, 85.89670101835478], [1, 0.36889259526491536, 87.17604731995854], [2, 0.3517718464717292, 87.6992499542655], [3, 0.35526543692939927, 87.57607171168974], [4, 0.3493265717198808, 87.76266845539362], [5, 0.35079776836259874, 87.47362644063662], [6, 0.34534544340812845, 87.96268065125923], [7, 0.35734797465540874, 87.72608085858894], [8, 0.3524193228360457, 87.63339228001708], [9, 0.35447056082407136, 88.0382950179889]]\n", + "0.0005: [[0, 0.4435185831906085, 85.1039697542533], [1, 0.37539843543085405, 86.94310628696871], [2, 0.35873422210283473, 87.3797182755046], [3, 0.34818319706667605, 87.93097140069517], [4, 0.34545205666010914, 87.86633331300689], [5, 0.3371337376732536, 88.10415269223734], [6, 0.33852135716659976, 88.11512897127874], [7, 0.33852605533302293, 88.14074028904201], [8, 0.33997187332225476, 88.21025672297091], [9, 0.3402654077747311, 88.1968412708092]]\n", + "0.0001: [[0, 0.6723326555745278, 79.72437343740472], [1, 0.5084800024207409, 83.89901823281907], [2, 0.45863669222676995, 84.88932251966584], [3, 0.42524330169194946, 85.90767729739618], [4, 0.4028480564841242, 86.33575218001097], [5, 0.38621816764383715, 86.9126166229648], [6, 0.3782781209337544, 87.11506799195074], [7, 0.3759017101781045, 87.00530520153667], [8, 0.3668581307538772, 87.32117812061712], [9, 0.3569657983208967, 87.71754375266785]]\n", + "1e-05: [[0, 1.8116753936371826, 54.021586682114766], [1, 1.3575628893609724, 63.8148667601683], [2, 1.0996285610935432, 69.48716385145435], [3, 0.9349309672803477, 73.7788889566437], [4, 0.8294046315685635, 76.08878590157937], [5, 0.7614829346374863, 77.91938532837368], [6, 0.7032811826737176, 79.30727483383133], [7, 0.6657257149818349, 80.09024940545156], [8, 0.6363296165202226, 80.82931886090616], [9, 0.6094131586890139, 81.52570278675529]]\n" + ] + } + ], + "source": [ + "lrs = [0.1, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00001]\n", + "for l in lrs:\n", + " with open(train_dir+\"/results:128:\"+str(l)+\".pkl\", \"rb\") as f:\n", + " res = pickle.load(f)\n", + " # print(str(l)+\": \" + str(np.amax(res[\"test\"], axis=0)))#+ str(np.max(res[\"test\"]))\n", + " print(str(l)+\": \" + str(res[\"test\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HGpNYzG_s-yJ", + "outputId": "783622a5-249f-4dd8-d242-fc6dfa47443c" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using cache found in /home/jeffrey/.cache/torch/hub/pytorch_vision_v0.10.0\n" + ] + } + ], + "source": [ + "import torch\n", + "resnet = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uZFgT6wss-yL", + "outputId": "10f8fc51-abb7-4c2b-f608-85229f3de29d", + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11699132\n" + ] + } + ], + "source": [ + "total = 0\n", + "for i in resnet.state_dict().values():\n", + " total += i.flatten().size(dim=0)\n", + "print(total)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizer analysis <a class=\"anchor\" id=\"optim\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "id": "mRZYP5UNs-yL" + }, + "outputs": [], + "source": [ + "# internal state test\n", + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)\n", + "old = model.state_dict()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0877, -0.1623, -0.0757, -0.1486, 0.1212, 0.1070, 0.0221, -0.1306,\n", + " 0.0798, -0.1525, -0.0297, -0.1715, 0.1039, 0.0143, 0.0982, 0.0428,\n", + " -0.0983, -0.0698, 0.1894, 0.1400, 0.0139, -0.0640, 0.0410, -0.0332,\n", + " -0.0993, -0.0840, -0.1224, 0.0723, 0.1994, 0.0017, -0.1309, 0.0044])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "old[\"conv1.bias\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1695, 0.0365, 0.0043, -0.0058, 0.1130, 0.1614, -0.1921, 0.0229,\n", + " 0.1472, 0.0111, -0.1327, -0.0368, 0.0536, -0.0637, 0.1539, 0.1022,\n", + " 0.1948, -0.1443, 0.1046, 0.1746, 0.1998, -0.0572, 0.0675, -0.1533,\n", + " -0.1863, -0.0397, 0.1823, -0.0121, 0.0045, 0.0704, 0.1362, 0.1068])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.state_dict()[\"conv1.bias\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0877, -0.1623, -0.0757, -0.1486, 0.1212, 0.1070, 0.0221, -0.1306,\n", + " 0.0798, -0.1525, -0.0297, -0.1715, 0.1039, 0.0143, 0.0982, 0.0428,\n", + " -0.0983, -0.0698, 0.1894, 0.1400, 0.0139, -0.0640, 0.0410, -0.0332,\n", + " -0.0993, -0.0840, -0.1224, 0.0723, 0.1994, 0.0017, -0.1309, 0.0044])" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "old[\"conv1.bias\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'state': {},\n", + " 'param_groups': [{'lr': 0.0005,\n", + " 'betas': (0.9, 0.999),\n", + " 'eps': 1e-08,\n", + " 'weight_decay': 0,\n", + " 'amsgrad': False,\n", + " 'params': [0, 1, 2, 3, 4, 5, 6, 7]}]}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "optimizer.state_dict()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n" + ] + } + ], + "source": [ + "for p in model.parameters():\n", + " print(type(p))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(optimizer.param_groups[0][\"params\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "ename": "IndexError", + "evalue": "list index out of range", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [19]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparam_groups\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\n", + "\u001b[0;31mIndexError\u001b[0m: list index out of range" + ] + } + ], + "source": [ + "optimizer.param_groups[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['params', 'lr', 'betas', 'eps', 'weight_decay', 'amsgrad'])" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "optimizer.param_groups[0].keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Parameter containing:\n", + "tensor([-0.0877, -0.1623, -0.0757, -0.1486, 0.1212, 0.1070, 0.0221, -0.1306,\n", + " 0.0798, -0.1525, -0.0297, -0.1715, 0.1039, 0.0143, 0.0982, 0.0428,\n", + " -0.0983, -0.0698, 0.1894, 0.1400, 0.0139, -0.0640, 0.0410, -0.0332,\n", + " -0.0993, -0.0840, -0.1224, 0.0723, 0.1994, 0.0017, -0.1309, 0.0044],\n", + " requires_grad=True)" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "optimizer.param_groups[0][\"params\"][1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# --> yes the optimizer values do not get updates" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "defaultdict(dict, {})" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "optimizer.state" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# optimizer.state is a dictionary that gets filled during the first step() call\n", + "# as keys it has the params and as values it has the internal state of the optimizer (first momentum, second momentum etc)\n", + "# stored the values in vals, they are from running the training loop" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(vals)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "vals_list = list(vals)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(vals_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'step': 69,\n", + " 'exp_avg': tensor([-1.4137e-03, -1.0432e-02, -5.7605e-03, -1.5292e-02, -1.1802e-02,\n", + " 1.1299e-03, 2.1533e-03, -9.7591e-03, -8.8733e-03, -4.7788e-03,\n", + " -1.9228e-03, -5.7594e-03, -5.4949e-05, -3.8590e-05, 1.3072e-04,\n", + " -7.8018e-03, -6.1446e-04, -2.9151e-03, -3.3301e-03, -2.0083e-03,\n", + " -3.0533e-03, -3.5316e-04, -8.1218e-03, 5.7864e-04, 5.8342e-04,\n", + " -1.1397e-02, -8.2111e-04, -6.8639e-03, -7.7449e-04, 1.0854e-04,\n", + " -4.7743e-05, -9.0613e-03]),\n", + " 'exp_avg_sq': tensor([9.6760e-06, 2.4495e-05, 8.1120e-06, 3.0419e-05, 1.0932e-05, 2.3003e-05,\n", + " 1.9296e-05, 1.5492e-05, 2.6551e-06, 1.1472e-05, 2.6787e-05, 9.0655e-05,\n", + " 8.7915e-11, 3.1380e-05, 4.9582e-06, 3.9729e-06, 7.5247e-06, 1.8417e-05,\n", + " 6.9078e-06, 2.9552e-05, 5.0895e-06, 1.6462e-06, 2.1158e-06, 2.8078e-06,\n", + " 2.5839e-06, 2.6732e-05, 2.0372e-05, 9.5084e-07, 2.0701e-06, 1.2862e-06,\n", + " 1.5106e-06, 2.5722e-05])}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vals_list[1] # entry for " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The most feasible solution would be to create a new optimizer and then \n", + "# vals = list(optimizer.state.values())\n", + "# create new optimizer\n", + "# for i, k in enmumerate(optimizer.param_groups[0][\"params\"]):\n", + "# optimizer.state[k] = vals[i]\n", + "# https://pytorch.org/docs/stable/_modules/torch/optim/adam.html#Adam\n", + "# https://pytorch.org/docs/stable/_modules/torch/optim/optimizer.html#Optimizer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## FFT <a class=\"anchor\" id=\"fft\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856, 1, 28, 28)" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_x\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5748.875" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "735856 / 128" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "weights = {}" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.124378 [ 0/735856]\n", + "loss: 1.539611 [64000/735856]\n", + "loss: 0.719579 [128000/735856]\n", + "loss: 0.685157 [192000/735856]\n", + "loss: 0.778637 [256000/735856]\n", + "loss: 0.493262 [320000/735856]\n", + "loss: 0.423785 [384000/735856]\n", + "loss: 0.531239 [448000/735856]\n", + "loss: 0.803173 [512000/735856]\n", + "loss: 0.498672 [576000/735856]\n", + "loss: 0.453685 [640000/735856]\n", + "loss: 0.355350 [704000/735856]\n", + "loss: 0.417364 [768000/735856]\n", + "loss: 0.462418 [832000/735856]\n", + "loss: 0.361217 [896000/735856]\n", + "loss: 0.484760 [960000/735856]\n", + "loss: 0.360997 [1024000/735856]\n", + "loss: 0.353997 [1088000/735856]\n", + "loss: 0.378490 [1152000/735856]\n", + "loss: 0.376164 [1216000/735856]\n", + "loss: 0.375268 [1280000/735856]\n", + "loss: 0.570408 [1344000/735856]\n", + "loss: 0.295247 [1408000/735856]\n", + "loss: 0.257762 [1472000/735856]\n", + "loss: 0.609368 [1536000/735856]\n", + "loss: 0.423437 [1600000/735856]\n", + "loss: 0.363265 [1664000/735856]\n", + "loss: 0.393251 [1728000/735856]\n", + "loss: 0.353971 [1792000/735856]\n", + "loss: 0.279443 [1856000/735856]\n", + "loss: 0.532804 [1920000/735856]\n", + "loss: 0.364327 [1984000/735856]\n", + "loss: 0.310962 [2048000/735856]\n", + "loss: 0.306962 [2112000/735856]\n", + "loss: 0.391289 [2176000/735856]\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "batch = 0\n", + "for e in range(3):\n", + " #training\n", + " for X, y in train_dataloader:\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " weight = {}\n", + " for k,v in model.state_dict().items():\n", + " weight[k] = v.clone()\n", + " \n", + " weights[str(batch)] = weight\n", + " batch += 1" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.2%, Avg loss: 0.367197 \n", + "\n" + ] + } + ], + "source": [ + "size = len(test_dataloader.dataset)\n", + "num_batches = len(test_dataloader)\n", + "model.eval()\n", + "test_loss, correct = 0, 0\n", + "with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + "test_loss /= num_batches\n", + "correct /= size\n", + "print(\"epoch:\")\n", + "print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + "stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['0', '500', '1000', '1500', '2000', '2500', '3000', '3500', '4000', '4500', '5000', '5500', '6000', '6500', '7000', '7500', '8000', '8500', '9000', '9500', '10000', '10500', '11000', '11500', '12000', '12500', '13000', '13500', '14000', '14500', '15000', '15500', '16000', '16500', '17000'])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weights.keys()" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "with open(\"vecs.pkl\", \"wb\") as f:\n", + " \n", + " json.dump(weights, f)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* 1d on flattend\n", + "* 1d on layers\n", + "* nd on layers" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "# working on the random initialization\n", + "flat = []\n", + "for v in weights[\"17000\"].values():\n", + " flat.append(v.flatten())\n", + "conc = torch.cat(flat)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1690046" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(conc)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1440, -0.0482, 0.2070, -0.2534, -0.2413, 0.0336, -0.2401, 0.2761,\n", + " 0.2361, -0.2687])" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "conc[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "import torch.fft as fft" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1690046" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft = fft.fft(conc)\n", + "len(flat_fft)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "845024" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft = fft.rfft(conc)\n", + "len(flat_fft)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-3912.2754+0.0000j, -685.3215+117.2780j, -718.2836-68.4478j,\n", + " ..., 33.0949-6.6868j, 49.2176+6.2663j,\n", + " -9.9980+0.0000j])" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "reverse = fft.irfft(flat_fft)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1440, -0.0482, 0.2070, -0.2534, -0.2413, 0.0336, -0.2401, 0.2761,\n", + " 0.2361, -0.2687])" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.0004)" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc - reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "top10 = torch.zeros(flat_fft.size(dim=0), dtype = torch.cfloat)\n", + "top10[0:84502] = flat_fft[0:84502]" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-3912.2754+0.0000j, -685.3215+117.2780j, -718.2836-68.4478j,\n", + " ..., 0.0000+0.0000j, 0.0000+0.0000j,\n", + " 0.0000+0.0000j])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top10" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "reverse_t10 = fft.irfft(top10)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0439, -0.0400, -0.0357, -0.0312, -0.0269, -0.0229, -0.0193, -0.0162,\n", + " -0.0134, -0.0109])" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_t10[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(40.2866)" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_t10 - reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "d10 = torch.zeros(flat_fft.size(dim=0), dtype = torch.cfloat)\n", + "d10[-84502:] = flat_fft[-84502:]" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "reverse_d10 = fft.irfft(d10)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0026, 0.0042, -0.0056, 0.0065, -0.0065, 0.0053, -0.0029, -0.0008,\n", + " 0.0059, -0.0120])" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_d10[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(43.7672)" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_d10 - reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "rand = torch.rand(conc.size(dim=0))" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(754.6744)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(rand - reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(29442.5273)" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_d10 - reverse, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(27450.3555)" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_t10 - reverse, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(30432.2695)" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-3912.2754+0.0000j, -685.3215+117.2780j, -718.2836-68.4478j,\n", + " ..., 33.0949-6.6868j, 49.2176+6.2663j,\n", + " -9.9980+0.0000j])" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([3912.2754, 695.2839, 721.5375, ..., 33.7637, 49.6149,\n", + " 9.9980])" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft.abs()" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(torch.arange(0,len(conc)), conc, '.')\n", + "plt.title('Parameter Values') \n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.draw()\n", + "plt.savefig(\"Parameter_Values.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(torch.arange(0,len(flat_fft)), flat_fft.abs(), '.')\n", + "plt.title('Model Fourier Frequency Representation') \n", + "plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.draw()\n", + "plt.savefig(\"Parameter_Frequency.png\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Normalizing" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(-0.0023)" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.mean(conc)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "conc2 = conc #+ 0.0016" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(-0.0023)" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.mean(conc2)" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "flat_fft2 = fft.rfft(conc)" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x7ff775a99c10>]" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(torch.arange(0,len(conc2)), conc2, '.')" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x7ff7759c01f0>]" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(torch.arange(0,len(flat_fft2)), flat_fft2.abs(), '.')" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [], + "source": [ + "topk = torch.topk(\n", + " flat_fft2.abs(), round(0.1*len(flat_fft2)), dim=0, sorted=False\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.return_types.topk(\n", + "values=tensor([ 75.7603, 695.2839, 721.5375, ..., 68.1649, 68.1649, 68.1649]),\n", + "indices=tensor([294037, 1, 2, ..., 241565, 434039, 328013]))" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([294037, 1, 2, ..., 241565, 434039, 328013])" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk.indices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [], + "source": [ + "top10 = torch.zeros(len(flat_fft2), dtype = torch.cfloat)\n", + "top10[topk.indices] = flat_fft2[topk.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "84502" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(topk.indices)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "reverse_top10 = fft.irfft(top10)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(34.8182)" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_top10 - conc2, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc2, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(30254.6758)" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_top10 - conc2, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [], + "source": [ + "topk_og = torch.topk(\n", + " conc2.abs(), round(0.1*len(conc2)), dim=0, sorted=False\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "169005" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(topk_og.indices)" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 1, 2, 3, 4, 0, 6, 7, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 21,\n", + " 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 40, 41, 42,\n", + " 44, 45, 46, 47, 48, 49, 39])" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk_og.indices[topk_og.indices<50]" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [], + "source": [ + "top10_og = torch.zeros(len(conc2))\n", + "top10_og[topk_og.indices] = conc2[topk_og.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(15.5541)" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - conc2, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(15858.2695)" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - conc2, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0058, -0.0441, -0.0381, -0.0493, -0.0240, 0.0190, -0.0132, -0.0221,\n", + " -0.0472, 0.0077, 0.0236, 0.0183, 0.0231, 0.0014, -0.0245, -0.0085,\n", + " 0.0035, -0.0036, 0.0150, 0.0107, 0.0123, 0.0039, 0.0003, -0.0320,\n", + " -0.0093, 0.0632, 0.0360, 0.0200, -0.0248, 0.0029, -0.0011, -0.0193,\n", + " 0.0221, 0.0056, -0.0091, -0.0008, 0.0329, 0.0133, -0.0078, -0.0061,\n", + " -0.0372, -0.0354, -0.0238, -0.0028, 0.0145, -0.0121, -0.0517, -0.0468,\n", + " -0.0123, -0.0132])" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_top10[10000:10050]" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0155, 0.0128, -0.0386, 0.0186, 0.0166, 0.0259, -0.0200, -0.0033,\n", + " -0.0399, 0.0214, 0.0106, 0.0197, -0.0182, -0.0191, -0.0370, 0.0159,\n", + " 0.0071, -0.0321, -0.0166, -0.0082, 0.0090, 0.0291, 0.0117, 0.0011,\n", + " 0.0066, 0.0163, 0.0237, 0.0092, -0.0029, -0.0209, -0.0207, 0.0039,\n", + " 0.0065, 0.0057, 0.0316, -0.0262, -0.0342, -0.0115, 0.0149, -0.0175,\n", + " -0.0568, -0.0135, -0.0503, -0.0252, 0.0148, -0.0429, -0.0424, -0.0182,\n", + " -0.0002, -0.0341])" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "conc2 [10000:10050]" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0000, 0.0000, -0.0386, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " -0.0399, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, -0.0370, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " -0.0568, 0.0000, -0.0503, 0.0000, 0.0000, -0.0429, -0.0424, 0.0000,\n", + " 0.0000, 0.0000])" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top10_og[10000:10050]" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1440, -0.0482, 0.2070, ..., 0.0011, 0.0177, -0.0218])" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "conc2[0:10000]" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [], + "source": [ + "reverse_top10fft = reverse_top10" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Qho4AaaTgWEIKoaUkre85S1cffXVtLW1sXfvXgKBAP/93/89Yt94PM7s2bNHzB/Ix1//+tdxawbl45Of/CRbtmzh97//Pe9973tJJpMlPS6RSFR8LTpjMQQTuR6D8jGbBE01hs5QIXJHVoZOkBzB1K9gIvjbTdC5rbLP2bIWXn9rwbsfffRRHA4H//zP/wyoITW33XYbCxcu5POf/zy/+93v+OMf/0ggECCRSHD33Xdz5ZVXsn37dkKhEDfccAPbt29n+fLlHD9+nDvvvJMNGzbQ2trK5s2bCQQCvP71r+f888/n2WefZc6cOdx///1UVVXxox/9iB/+8IdEo1GWLFnCz3/+85LnBaxcuRKLxUJvby833ngjR48eJRwO84lPfIIbb7wRAJfLxb/8y7/w8MMPc+edd/Loo4/ypz/9ieHhYc4991x+8IMfIIRg48aNnHrqqTz11FMEg0F+9rOf8ZWvfIVt27bxjne8g1tuuQWAX/ziF9xxxx1Eo1HOOussvvvd7/Lf//3fKfXW1atX88tf/jLvfmazecR6/vznP/PAAw9gsVi49NJL83pBBgYnAnpTma5CqkJDU38aNjyCCrFjxw5OP/30rG1ut5v58+ezb98+AF5++WXuuecennjiiaz9vvvd71JbW8vOnTv54he/yEsvvZT3GG1tbXzkIx9hx44deL1e/vCHPwDwlre8hRdffJGtW7eycuVK/u///q/kdW/atAmTyURjYyM/+clPeOmll9i8eTN33HEHfX19AASDQc466yy2bt3K+eefz0c/+lFefPFFtm/fzvDwcJayqs1mY/PmzXzwgx/kTW96E3feeSfbt2/nrrvuoq+vj127dvHb3/6WZ555hi1btmA2m/nlL3/JrbfemlJv/eUvf1lwv9z1rFy5knvvvZcdO3bw6quv8tnPfrbk125gMNnUV9uwmkXKIwhE4lMuQQ3T1SMocuU+lVxyySXU1dWN2P7000/ziU98AoA1a9awbt26vI9fuHAh69evB+D000/n0KFDAGzfvp3PfvazDA4OEggEuOyyy0Zdy2233cYvfvELampq+O1vf4sQgjvuuIN7770XgKNHj9LW1kZ9fT1ms5m3vvWtqcc+9thjfO1rXyMUCtHf38/q1at54xvfCCgBO4C1a9eyevXqlHjdokWLOHr0KE8//TQvvfQSZ5xxBqBmODQ1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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(np.arange(100000,100050,1), reverse_top10fft[100000:100050], label = \"FFT top-10%\")\n", + "plt.plot(np.arange(100000,100050,1), conc2[100000:100050], label = \"Original Parameters\")\n", + "plt.plot(np.arange(100000,100050,1), top10_og[100000:100050], label = \"Parameter top-10%\")\n", + "plt.title('Parameter Values') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.legend()\n", + "plt.draw()\n", + "plt.savefig(\"Parameters.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(conc2.numpy(), 100, (-0.1,0.1))\n", + "plt.title('Parameter Values Histogram') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter values\")\n", + "plt.draw()\n", + "plt.savefig(\"Parameter_Histogram.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(reverse_top10.numpy(), 100, (-0.1,0.1))\n", + "plt.title('Top-10% FFT Reconstructed Parameter Values Histogram') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter values\")\n", + "plt.draw()\n", + "plt.savefig(\"FFT_Histogram.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(top10_og[top10_og.abs() >0].numpy(), 100, (-0.1,0.1))\n", + "plt.title('Top-10% Parameter Values Histogram') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter values\")\n", + "plt.draw()\n", + "plt.savefig(\"top10_Histogram.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.14400896, -0.04817872, 0.20703338, ..., 0.0729612 ,\n", + " -0.06001848, -0.03798665], dtype=float32)" + ] + }, + "execution_count": 86, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top10_og[top10_og.abs() >0].numpy()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Per Layer" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": {}, + "outputs": [], + "source": [ + "flat5000 = []\n", + "for v in weights[\"17000\"].values():\n", + " flat5000.append(v.flatten())\n", + "conc500 = torch.cat(flat5000)" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc500, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 134, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(3.8334)\n", + "tensor(0.5911)\n", + "tensor(14.2745)\n", + "tensor(0.2714)\n", + "tensor(29.4115)\n", + "tensor(0.4823)\n", + "tensor(9.3226)\n", + "tensor(0.3447)\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "errs = []\n", + "lens = []\n", + "fft_layers = []\n", + "for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " lens.append(len(flat))\n", + " flat_fft = fft.rfft(flat)\n", + " topk = torch.topk(\n", + " flat_fft.abs(), round(0.1*len(flat_fft)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + " top10[topk.indices] = flat_fft[topk.indices]\n", + " reverse_top10 = fft.irfft(top10)\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " print(err)\n", + " errs.append(err*err)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[800, 32, 51200, 64, 1605632, 512, 31744, 62]" + ] + }, + "execution_count": 135, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lens" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1171.1743" + ] + }, + "execution_count": 136, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 137, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "34.222424" + ] + }, + "execution_count": 137, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [], + "source": [ + "fft_conc = torch.cat(fft_layers)" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'conc5000' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [94]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m torch\u001b[38;5;241m.\u001b[39mnorm(fft_conc \u001b[38;5;241m-\u001b[39m \u001b[43mconc5000\u001b[49m\n\u001b[1;32m 2\u001b[0m ,\u001b[38;5;241m2\u001b[39m)\n", + "\u001b[0;31mNameError\u001b[0m: name 'conc5000' is not defined" + ] + } + ], + "source": [ + "torch.norm(fft_conc - conc5000\n", + " ,2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Almost no difference in layerwise vs over the entire weight" + ] + }, + { + "cell_type": "code", + "execution_count": 138, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['0', '500', '1000', '1500', '2000', '2500', '3000', '3500', '4000', '4500', '5000', '5500', '6000', '6500', '7000', '7500', '8000', '8500', '9000', '9500', '10000', '10500', '11000', '11500', '12000', '12500', '13000', '13500', '14000', '14500', '15000', '15500', '16000', '16500', '17000'])" + ] + }, + "execution_count": 138, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weights.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 139, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(3.8017)\n", + "tensor(0.6525)\n", + "tensor(9.6627)\n", + "tensor(0.2314)\n", + "tensor(14.0121)\n", + "tensor(0.3602)\n", + "tensor(6.0212)\n", + "tensor(0.3187)\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "errs = []\n", + "lens = []\n", + "for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " lens.append(len(flat))\n", + " topk = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat))\n", + " top10[topk.indices] = flat[topk.indices]\n", + " err = torch.norm(top10 - flat, 2)\n", + " print(err)\n", + " errs.append(err*err)" + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[800, 32, 51200, 64, 1605632, 512, 31744, 62]" + ] + }, + "execution_count": 140, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lens" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 141, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "341.1233" + ] + }, + "execution_count": 141, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 142, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "18.469522" + ] + }, + "execution_count": 142, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [], + "source": [ + "flat5000 = []\n", + "for v in weights[\"17000\"].values():\n", + " flat5000.append(v.flatten())\n", + "conc5000 = torch.cat(flat5000)" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 100, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc5000, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(2.5049)\n", + "tensor(0.4643)\n", + "tensor(6.6074)\n", + "tensor(0.1233)\n", + "tensor(12.2971)\n", + "tensor(0.1902)\n", + "tensor(4.0843)\n", + "tensor(0.1482)\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "errs = []\n", + "errs1 = []\n", + "lens = []\n", + "fft_layers = []\n", + "for v in weights[\"1000\"].values():\n", + " flat = v.flatten()\n", + " lens.append(len(flat))\n", + " flat_fft = fft.rfft(flat)\n", + " topk = torch.topk(\n", + " flat_fft.abs(), round(0.2*len(flat_fft)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + " top10[topk.indices] = flat_fft[topk.indices]\n", + " reverse_top10 = fft.irfft(top10)\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " errs1.append(torch.norm(reverse_top10 - flat, 1))\n", + " print(err)\n", + " errs.append(err*err)" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[800, 32, 51200, 64, 1605632, 512, 31744, 62]" + ] + }, + "execution_count": 102, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lens" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "218.12065" + ] + }, + "execution_count": 103, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "14.7689085" + ] + }, + "execution_count": 104, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": {}, + "outputs": [], + "source": [ + "fft_conc = torch.cat(fft_layers)" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(39.6843)" + ] + }, + "execution_count": 106, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(fft_conc - conc5000,2)" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[tensor(57.1960),\n", + " tensor(2.2182),\n", + " tensor(1148.8655),\n", + " tensor(0.7960),\n", + " tensor(12109.6943),\n", + " tensor(3.3738),\n", + " tensor(578.7853),\n", + " tensor(0.9163)]" + ] + }, + "execution_count": 107, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "errs1" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "13901.846" + ] + }, + "execution_count": 108, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs1)" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(3.8017)\n", + "tensor(0.6525)\n", + "tensor(9.6627)\n", + "tensor(0.2314)\n", + "tensor(14.0121)\n", + "tensor(0.3602)\n", + "tensor(6.0212)\n", + "tensor(0.3187)\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "errs = []\n", + "lens = []\n", + "errs1 = []\n", + "for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " lens.append(len(flat))\n", + " topk = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat))\n", + " top10[topk.indices] = flat[topk.indices]\n", + " err = torch.norm(top10 - flat, 2)\n", + " print(err)\n", + " errs.append(err*err)\n", + " errs1.append(torch.norm(top10 - flat, 1))" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[800, 32, 51200, 64, 1605632, 512, 31744, 62]" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lens" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "341.1233" + ] + }, + "execution_count": 111, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 112, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "18.469522" + ] + }, + "execution_count": 112, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[tensor(86.4496),\n", + " tensor(3.1551),\n", + " tensor(1531.9570),\n", + " tensor(1.5015),\n", + " tensor(14199.5361),\n", + " tensor(6.1879),\n", + " tensor(814.4448),\n", + " tensor(2.0511)]" + ] + }, + "execution_count": 113, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "errs1" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "16645.283" + ] + }, + "execution_count": 114, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs1)" + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n", + "None\n", + "None\n", + "None\n", + "None\n", + "None\n", + "None\n", + "None\n" + ] + } + ], + "source": [ + "flat5000 = []\n", + "for v in weights[\"17000\"].values():\n", + " print(v.grad)\n", + " flat5000.append(v.flatten())\n", + "conc5000 = torch.cat(flat5000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Wavelets <a class=\"anchor\" id=\"wt\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: PyWavelets in /home/jeffrey/anaconda3/envs/sacs39/lib/python3.9/site-packages (1.2.0)\n", + "Requirement already satisfied: numpy>=1.17.3 in /home/jeffrey/anaconda3/envs/sacs39/lib/python3.9/site-packages (from PyWavelets) (1.22.3)\n" + ] + } + ], + "source": [ + "!pip install PyWavelets" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [], + "source": [ + "import pywt" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "metadata": {}, + "outputs": [], + "source": [ + "#(cA, cD) = pywt.dwt(, 'db1')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# pywt.wavelist(kind='discrete', )" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 18.427034\n", + "db1 18.427034\n", + "sym2 18.36348\n", + "coif1 18.393574\n", + "bior1.1 18.427034\n", + "rbio1.1 18.427034\n", + "dmey 18.671127\n", + "bior4.4 18.496372\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "for wavelet in wavelets:\n", + " errs = []\n", + " errs1 = []\n", + " lens = []\n", + " fft_layers = []\n", + " for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " #print(flat.shape)\n", + " lens.append(len(flat))\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " errs1.append(torch.norm(reverse_top10 - flat, 1))\n", + " #print(err)\n", + " errs.append(err*err)\n", + " # print(flat[0:10])\n", + " # print(reverse_top10[0:10])\n", + " print(wavelet, np.sqrt(np.sum(errs)))" + ] + }, + { + "cell_type": "code", + "execution_count": 156, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bior1.1 15.07145881652832 16107.921875\n", + "bior1.3 15.25814437866211 16279.986328125\n", + "bior1.5 15.425777435302734 16436.12109375\n", + "bior2.2 15.66141128540039 16473.904296875\n", + "bior2.4 15.516386985778809 16417.8203125\n", + "bior2.6 15.544709205627441 16466.162109375\n", + "bior2.8 15.579778671264648 16503.138671875\n", + "bior3.1 25.344850540161133 24354.4453125\n", + "bior3.3 18.38104248046875 18552.30859375\n", + "bior3.5 17.479848861694336 17874.1015625\n", + "bior3.7 17.260520935058594 17713.20703125\n", + "bior3.9 17.19255828857422 17672.990234375\n", + "bior4.4 15.1978120803833 16241.7060546875\n", + "bior5.5 15.467646598815918 16527.41796875\n", + "bior6.8 15.204909324645996 16253.8125\n", + "coif1 15.142683029174805 16156.6630859375\n", + "coif2 15.175430297851562 16219.298828125\n", + "coif3 15.218149185180664 16275.017578125\n", + "coif4 15.248283386230469 16304.376953125\n", + "coif5 15.278726577758789 16337.1923828125\n", + "coif6 15.300649642944336 16357.455078125\n", + "coif7 15.324337005615234 16380.2119140625\n", + "coif8 15.34239387512207 16396.9453125\n", + "coif9 15.35299301147461 16408.88671875\n", + "coif10 15.358224868774414 16412.31640625\n", + "coif11 15.375347137451172 16429.083984375\n", + "coif12 15.383316993713379 16440.47265625\n", + "coif13 15.401575088500977 16450.142578125\n", + "coif14 15.413949012756348 16466.5859375\n", + "coif15 15.430389404296875 16478.208984375\n", + "coif16 15.438526153564453 16489.732421875\n", + "coif17 15.44447135925293 16493.5625\n", + "db1 15.07145881652832 16107.921875\n", + "db2 15.11799430847168 16146.3642578125\n", + "db3 15.206748008728027 16251.126953125\n", + "db4 15.276558876037598 16337.6650390625\n", + "db5 15.346190452575684 16396.228515625\n", + "db6 15.424012184143066 16471.95703125\n", + "db7 15.465736389160156 16520.9609375\n", + "db8 15.5084228515625 16558.216796875\n", + "db9 15.579204559326172 16622.1484375\n", + "db10 15.634806632995605 16672.583984375\n", + "db11 15.69124698638916 16721.88671875\n", + "db12 15.76386833190918 16791.78125\n", + "db13 15.807873725891113 16828.6328125\n", + "db14 15.84904956817627 16859.560546875\n", + "db15 15.879130363464355 16884.310546875\n", + "db16 15.916594505310059 16917.77734375\n", + "db17 15.97330093383789 16964.7890625\n", + "db18 16.010889053344727 17004.966796875\n", + "db19 16.06007957458496 17043.080078125\n", + "db20 16.109506607055664 17080.361328125\n", + "db21 16.15558433532715 17122.78125\n", + "db22 16.195322036743164 17152.8046875\n", + "db23 16.23825454711914 17190.244140625\n", + "db24 16.28815269470215 17229.99609375\n", + "db25 16.29660415649414 17237.244140625\n", + "db26 16.331958770751953 17263.62890625\n", + "db27 16.375545501708984 17302.498046875\n", + "db28 16.413320541381836 17331.599609375\n", + "db29 16.437959671020508 17352.27734375\n", + "db30 16.50661849975586 17411.228515625\n", + "db31 16.53733253479004 17433.791015625\n", + "db32 16.5701904296875 17458.037109375\n", + "db33 16.599777221679688 17484.1953125\n", + "db34 16.628063201904297 17505.951171875\n", + "db35 16.64190101623535 17514.66796875\n", + "db36 16.680456161499023 17541.33203125\n", + "db37 16.730104446411133 17587.6328125\n", + "db38 16.75263214111328 17598.830078125\n", + "dmey 15.428367614746094 16479.267578125\n", + "haar 15.07145881652832 16107.921875\n", + "rbio1.1 15.07145881652832 16107.921875\n", + "rbio1.3 15.1613130569458 16189.78125\n", + "rbio1.5 15.32840633392334 16338.216796875\n", + "rbio2.2 16.183170318603516 16984.47265625\n", + "rbio2.4 15.833732604980469 16793.46875\n", + "rbio2.6 15.841042518615723 16820.513671875\n", + "rbio2.8 15.870935440063477 16858.255859375\n", + "rbio3.1 112.47295379638672 58394.6875\n", + "rbio3.3 19.817306518554688 20010.50390625\n", + "rbio3.5 18.20765495300293 18729.5625\n", + "rbio3.7 17.90874671936035 18495.369140625\n", + "rbio3.9 17.855627059936523 18441.083984375\n", + "rbio4.4 15.365104675292969 16364.685546875\n", + "rbio5.5 15.447882652282715 16390.2890625\n", + "rbio6.8 15.320694923400879 16363.552734375\n", + "sym2 15.11799430847168 16146.3642578125\n", + "sym3 15.206748008728027 16251.126953125\n", + "sym4 15.159475326538086 16207.3779296875\n", + "sym5 15.204032897949219 16260.142578125\n", + "sym6 15.191091537475586 16246.744140625\n", + "sym7 15.236370086669922 16293.701171875\n", + "sym8 15.241791725158691 16298.5556640625\n", + "sym9 15.26644229888916 16327.4296875\n", + "sym10 15.264242172241211 16323.5576171875\n", + "sym11 15.332569122314453 16396.794921875\n", + "sym12 15.310770034790039 16371.40234375\n", + "sym13 15.304075241088867 16360.4248046875\n", + "sym14 15.317804336547852 16377.61328125\n", + "sym15 15.378673553466797 16436.265625\n", + "sym16 15.33505916595459 16392.92578125\n", + "sym17 15.344695091247559 16404.30859375\n", + "sym18 15.363746643066406 16418.08984375\n", + "sym19 15.430442810058594 16479.15625\n", + "sym20 15.377063751220703 16438.19140625\n", + "min: tensor(15.0715) bior1.1 0\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "#wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " #print(flat.shape)\n", + " lens.append(len(flat))\n", + " to_cat.append(flat)\n", + " flat = torch.cat(to_cat, dim=0)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 157, + "metadata": {}, + "outputs": [], + "source": [ + "topk_og = torch.topk(\n", + " conc2.abs(), round(0.1*len(conc2)), dim=0, sorted=False\n", + " )\n", + "top10_og = torch.zeros(len(conc2))\n", + "top10_og[topk_og.indices] = conc2[topk_og.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 158, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(15.5541)" + ] + }, + "execution_count": 158, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - conc2, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 159, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "42.212055" + ] + }, + "execution_count": 159, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "# Problem: weights with only a few parameters cannot be represented with the wavelets" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "metadata": {}, + "outputs": [], + "source": [ + "flat5000 = []\n", + "for v in weights[\"17000\"].values():\n", + " flat5000.append(v.flatten())\n", + "conc5000 = torch.cat(flat5000)" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc5000, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 149, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dmey tensor(15.4284)\n" + ] + } + ], + "source": [ + "wavelet = 'dmey'\n", + "coeff = pywt.wavedec(conc5000.numpy(), wavelet, level = None)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))" + ] + }, + { + "cell_type": "code", + "execution_count": 150, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(np.arange(100000,100050,1), reverse_top10fft[100000:100050], label = \"FFT top-10%\")\n", + "plt.plot(np.arange(100000,100050,1), conc2[100000:100050], label = \"Original Parameters\")\n", + "plt.plot(np.arange(100000,100050,1), reverse_top10[100000:100050], label = \"Haar top-10%\")\n", + "plt.title('Parameter Values') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.legend()\n", + "plt.draw()\n", + "plt.savefig(\"ParametersWaveletHaar.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 175, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar tensor(12.0875)\n" + ] + } + ], + "source": [ + "wavelet = 'haar'\n", + "coeff = pywt.wavedec(conc5000.numpy(), wavelet, level = None)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))" + ] + }, + { + "cell_type": "code", + "execution_count": 176, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar tensor(9.4642)\n" + ] + } + ], + "source": [ + "wavelet = 'haar'\n", + "coeff = pywt.wavedec(conc5000.numpy(), wavelet, level = None)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.2*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))" + ] + }, + { + "cell_type": "code", + "execution_count": 177, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "haar tensor(12.1470)\n", + "(52814,)\n", + "(52814,)\n", + "(105628,)\n", + "(211256,)\n", + "(422512,)\n", + "(845023,)\n", + "haar tensor(16.9818)\n", + "(52814,)\n", + "(52814,)\n", + "(105628,)\n", + "(211256,)\n", + "(422512,)\n", + "(845023,)\n", + "haar tensor(2.3811e-06)\n" + ] + } + ], + "source": [ + "wavelet = 'haar'\n", + "coeff = pywt.wavedec(conc5000.numpy(), wavelet, level = 5)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "print(len(coeff))\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))\n", + "\n", + "reduced = []\n", + "for i, o in enumerate(coeff):\n", + " print(o.shape) \n", + " if i > 3:\n", + " reduced.append(np.zeros_like(o))\n", + " continue\n", + " reduced.append(o)\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(reduced, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))\n", + "\n", + "reduced = []\n", + "for i, o in enumerate(coeff):\n", + " print(o.shape) \n", + " if i > 5:\n", + " reduced.append(np.zeros_like(o))\n", + " continue\n", + " reduced.append(o)\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(reduced, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# with resnet" + ] + }, + { + "cell_type": "code", + "execution_count": 178, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using cache found in /home/jeffrey/.cache/torch/hub/pytorch_vision_v0.10.0\n" + ] + } + ], + "source": [ + "model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 179, + "metadata": {}, + "outputs": [], + "source": [ + "resw = {}\n", + "for k,v in model.state_dict().items():\n", + " resw[k] = v.clone()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "flatr = []\n", + "for v in resw.values():\n", + " flatr.append(v.flatten())\n", + "concr = torch.cat(flatr)" + ] + }, + { + "cell_type": "code", + "execution_count": 190, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bior1.1 43.02796936035156 115077.1953125\n", + "bior1.3 44.042415618896484 117252.8203125\n", + "bior1.5 44.798824310302734 119106.71875\n", + "bior2.2 44.7282600402832 117956.5\n", + "bior2.4 44.04926300048828 116528.5078125\n", + "bior2.6 44.09769821166992 116693.171875\n", + "bior2.8 44.207454681396484 116984.125\n", + "bior3.1 65.93879699707031 171188.890625\n", + "bior3.3 52.62727355957031 136826.25\n", + "bior3.5 50.10884475708008 130465.40625\n", + "bior3.7 49.333717346191406 128473.21875\n", + "bior3.9 49.07342529296875 127796.1640625\n", + "bior4.4 42.742881774902344 114508.9921875\n", + "bior5.5 43.98085403442383 118580.4296875\n", + "bior6.8 42.57365417480469 113812.046875\n", + "coif1 42.74231719970703 114690.046875\n", + "coif2 42.56312561035156 114001.890625\n", + "coif3 42.54220199584961 113903.578125\n", + "coif4 42.558956146240234 113906.859375\n", + "coif5 42.56120681762695 113924.28125\n", + "coif6 42.592472076416016 113980.0390625\n", + "coif7 42.60406494140625 114030.09375\n", + "coif8 42.61618423461914 114052.2734375\n", + "coif9 42.6173095703125 114053.078125\n", + "coif10 42.63934326171875 114081.7890625\n", + "coif11 42.65342712402344 114141.3671875\n", + "coif12 42.65858840942383 114128.3984375\n", + "coif13 42.66160583496094 114154.7890625\n", + "coif14 42.68099594116211 114187.8828125\n", + "coif15 42.693885803222656 114239.90625\n", + "coif16 42.69415283203125 114222.0234375\n", + "coif17 42.69487762451172 114230.65625\n", + "db1 43.02796936035156 115077.1953125\n", + "db2 42.69436264038086 114436.171875\n", + "db3 42.692832946777344 114409.2578125\n", + "db4 42.69171905517578 114270.2265625\n", + "db5 42.7407341003418 114356.6796875\n", + "db6 42.832889556884766 114583.046875\n", + "db7 42.90106201171875 114756.140625\n", + "db8 42.927757263183594 114787.8671875\n", + "db9 42.980587005615234 114925.3125\n", + "db10 43.0425910949707 115035.796875\n", + "db11 43.09166717529297 115145.9609375\n", + "db12 43.11075210571289 115177.953125\n", + "db13 43.153038024902344 115282.9765625\n", + "db14 43.23004913330078 115438.109375\n", + "db15 43.254371643066406 115495.4375\n", + "db16 43.26611328125 115499.40625\n", + "db17 43.29021453857422 115553.8359375\n", + "db18 43.339332580566406 115670.8515625\n", + "db19 43.363834381103516 115699.546875\n", + "db20 43.3875732421875 115747.3046875\n", + "db21 43.406944274902344 115809.53125\n", + "db22 43.44538879394531 115883.546875\n", + "db23 43.48051071166992 115981.046875\n", + "db24 43.502601623535156 115997.3203125\n", + "db25 43.519954681396484 116035.3359375\n", + "db26 43.53356170654297 116078.15625\n", + "db27 43.55718994140625 116114.859375\n", + "db28 43.56884765625 116135.7421875\n", + "db29 43.60223388671875 116207.0390625\n", + "db30 43.6269645690918 116254.625\n", + "db31 43.62778091430664 116261.8984375\n", + "db32 43.65283966064453 116317.5546875\n", + "db33 43.683868408203125 116371.8046875\n", + "db34 43.71052551269531 116451.03125\n", + "db35 43.69470977783203 116395.71875\n", + "db36 43.722896575927734 116448.71875\n", + "db37 43.732479095458984 116494.3203125\n", + "db38 43.75498962402344 116516.2890625\n", + "dmey 42.70671844482422 114251.421875\n", + "haar 43.02796936035156 115077.1953125\n", + "rbio1.1 43.02796936035156 115077.1953125\n", + "rbio1.3 42.904876708984375 114998.609375\n", + "rbio1.5 43.487056732177734 116603.4375\n", + "rbio2.2 48.12295150756836 128830.65625\n", + "rbio2.4 45.82650375366211 123338.625\n", + "rbio2.6 45.57454299926758 122649.625\n", + "rbio2.8 45.610652923583984 122736.25\n", + "rbio3.1 323.1489562988281 493834.4375\n", + "rbio3.3 63.0237922668457 168654.40625\n", + "rbio3.5 55.14375686645508 147856.1875\n", + "rbio3.7 53.33525466918945 143081.296875\n", + "rbio3.9 52.70606994628906 141449.8125\n", + "rbio4.4 43.57114028930664 116553.6171875\n", + "rbio5.5 43.684425354003906 115561.5078125\n", + "rbio6.8 43.01945495605469 115265.328125\n", + "sym2 42.69436264038086 114436.171875\n", + "sym3 42.692832946777344 114409.2578125\n", + "sym4 42.546844482421875 113956.859375\n", + "sym5 42.57182693481445 113959.1640625\n", + "sym6 42.52703094482422 113885.0546875\n", + "sym7 42.550376892089844 113925.90625\n", + "sym8 42.56036376953125 113907.7109375\n", + "sym9 42.602020263671875 114008.0625\n", + "sym10 42.568580627441406 113940.015625\n", + "sym11 42.623958587646484 114091.0546875\n", + "sym12 42.602752685546875 114007.203125\n", + "sym13 42.62556076049805 114069.9375\n", + "sym14 42.608367919921875 114038.21875\n", + "sym15 42.66935348510742 114179.7578125\n", + "sym16 42.629066467285156 114064.859375\n", + "sym17 42.639869689941406 114103.421875\n", + "sym18 42.6433219909668 114109.6328125\n", + "sym19 42.72231674194336 114301.625\n", + "sym20 42.658966064453125 114131.046875\n", + "min: tensor(42.5270) sym6 91\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "#wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " for v in resw.values():\n", + " flat = v.flatten()\n", + " #print(flat.shape)\n", + " lens.append(len(flat))\n", + " to_cat.append(flat)\n", + " flat = torch.cat(to_cat, dim=0)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 181, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "11699132" + ] + }, + "execution_count": 181, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(concr)" + ] + }, + { + "cell_type": "code", + "execution_count": 197, + "metadata": {}, + "outputs": [], + "source": [ + "topk_og = torch.topk(\n", + " concr.abs(), round(0.1*len(concr)), dim=0, sorted=False\n", + " )\n", + "top10_og = torch.zeros(len(concr))\n", + "top10_og[topk_og.indices] = concr[topk_og.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 198, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(47.3773)" + ] + }, + "execution_count": 198, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - concr, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 199, + "metadata": {}, + "outputs": [], + "source": [ + "to_cat = []\n", + "for v in resw.values():\n", + " flat = v.flatten()\n", + " to_cat.append(flat)\n", + "flat = torch.cat(to_cat, dim=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 200, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(71.3879)\n" + ] + } + ], + "source": [ + "flat_fft = fft.rfft(flat)\n", + "topk = torch.topk(\n", + " flat_fft.abs(), round(0.1*len(flat_fft)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + "top10[topk.indices] = flat_fft[topk.indices]\n", + "reverse_top10fft = fft.irfft(top10)\n", + "fft_layers.append(reverse_top10fft)\n", + "err = torch.norm(reverse_top10fft - flat, 2)\n", + "print(err)" + ] + }, + { + "cell_type": "code", + "execution_count": 201, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(42.6944)\n" + ] + } + ], + "source": [ + "coeff = pywt.wavedec(flat.numpy(), \"sym2\", level = None)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10wv = torch.from_numpy(pywt.waverec(og, wavelet = \"sym2\"))\n", + "err = torch.norm(reverse_top10wv - flat, 2)\n", + "print(err)" + ] + }, + { + "cell_type": "code", + "execution_count": 202, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(np.arange(100000,100050,1), reverse_top10fft[100000:100050], label = \"FFT top-10%\")\n", + "plt.plot(np.arange(100000,100050,1), concr[100000:100050], label = \"Original Parameters\")\n", + "plt.plot(np.arange(100000,100050,1), reverse_top10wv[100000:100050], label = \"Sym2 top-10%\")\n", + "\n", + "plt.title('Parameter Values') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.legend()\n", + "plt.draw()\n", + "plt.savefig(\"ParametersWaveletHaar.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 203, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0000, 0.0649, 0.0881, 0.0000, 0.0464, 0.0347, -0.0472, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, -0.0365, 0.0000,\n", + " -0.0422, -0.0344, 0.0372, -0.0823, 0.0000, 0.0764, -0.1654, 0.0000,\n", + " 0.0000, -0.0363, -0.0769, 0.0896, 0.0000, 0.0955, 0.0000, -0.0843,\n", + " 0.0000, -0.0387, 0.1598, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000])" + ] + }, + "execution_count": 203, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top10_og[100000:100050]" + ] + }, + { + "cell_type": "code", + "execution_count": 204, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAEWCAYAAABrDZDcAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAACHdklEQVR4nO2ddXhUV/rHP2cmE3d3gQRKEkJwiluLLAXqQlu69a1uZbdUfvXutt1u3d2FGqVdWkpLKe4ElwQIRIm7Z87vjzsTJsnESCAy5/M8eSZz77l3zk1m5r3nle8rpJQoFAqFwnbRdfcEFAqFQtG9KEOgUCgUNo4yBAqFQmHjKEOgUCgUNo4yBAqFQmHjKEOgUCgUNo4yBApFL0cIMVkIkd7d81D0XpQhUHQrQohUIUSlEKJMCHFCCPGhEMK1u+fVGkKISCGEFELYddH5HIUQRUKIqVb2vSCE+KYrXkehaAllCBQ9gfOklK7AMGAE8FBHDhYavea93NSASCmrgK+Aq5uM0wOXAx+dudkpbJFe8+FR9H2klBnAz0C8EMJLCPGTECJXCFFo+j3UPFYIsUoI8ZQQYh1QAfQTQvxVCLFfCFEqhDgihLjJYvxkIUS6EOKfQogcIUSWEGK+EGK2EOKQEKJACPGAxXidEGKREOKwECJfCLFYCOFt2r3a9FhkWsmcbTrmWtPrFwohlgshIizOJ4UQtwohkoFkK5f/EXChEMLZYtsMtM/oz61dW1NMrxVt8fxDIcSTFs/nCCGSTKuQ9UKIBIt99wkhMkyvc1AIMa2l11H0HZQhUPQYhBBhwGxgB9p78wMgAggHKoFXmxxyFXAj4AYcA3KAOYA78FfgBSHEMIvxgYAjEAI8DLwDXAkMByYA/yeEiDKNvR2YD0wCgoFC4DXTvommR08ppauUcoMQYh7wAHAB4AesAb5oMt/5wGggtum1SynXA1mm4y2v73MpZV07rq1dCCGGAu8DNwE+wFvAUiGEgxBiIHAbMFJK6YZmiFI7+hqKXoiUUv2on277QfuiKQOK0L7MXwecrIxLBAotnq8CHm/j3EuAO02/T0YzJnrTczdAAqMtxm8D5pt+3w9Ms9gXBNQCdkCk6Vg7i/0/A9dZPNehrVQiTM8lMLWN+T4E/Gr63d10/NB2Xlu6xT4JRFs8/xB40vT7G8ATTc51EM3gRaMZnOmAobvfG+rnzP2oFYGiJzBfSukppYyQUt4ipawUQjgLId4SQhwTQpSguWM8TX5zM2mWJxFCzBJCbDS5eYrQVhe+FkPypZT1pt8rTY8nLPZXAuZAdQTwvcl9UoRmGOqBgBauIQJ4yWJ8ASDQVh9W52uFT4ApQohg4CLgsJRyRzuvrb1EAPeY52k6VxgQLKVMAf4OPArkCCG+NM1F0cdRhkDRU7kHGIh2x+7OSXeMsBjTIJ0rhHAAvgWeAwKklJ7AsibjO0IaMMtkoMw/jlKLY1iT7E0Dbmoy3klqLp9m87WGlPIYmkvpSjS30EeneG0VgGWsIbDJPJ9qMk9nKeUXpjl8LqUcj2YwJPBMa3NW9A2UIVD0VNzQ7tCLTEHaR9oYbw84ALlAnRBiFnBuJ17/TeApc8BXCOFnigNgeg0j0K/J+PuFEHGm8R5CiItP4XU/QvPTjwM+M23r6LUlAVcIIfRCiJlobh8z7wA3CyFGm7KtXIQQfxFCuAkhBgohppoMTxXa3994Cteg6GUoQ6DoqbwIOAF5wEbgl9YGSylLgTuAxWiB3SuApZ14/ZdMx/8qhCg1zWG06bUqgKeAdSb3yhgp5fdod89fmlxZe4BZp/C63wLewO9SyqxTvLY7gfPQ4i4L0OIJmM61FbgBLfBeCKQA15h2OwBPo/3NswF/4P5TuAZFL0NIqRrTKBQKhS2jVgQKhUJh4yhDoFAoFDaOMgQKhUJh4yhDoFAoFDZOl6gnnml8fX1lZGRkd09DoVAoehXbtm3Lk1L6Nd3eKw1BZGQkW7du7e5pKBQKRa9CCHHM2nblGlIoFAobRxkChUKhsHGUIVAoFAobp1fGCKxRW1tLeno6VVVV3T0VRQ/C0dGR0NBQDAZDd09Foeix9BlDkJ6ejpubG5GRkQhxqoKTir6ElJL8/HzS09OJiopq+wCFwkbpM66hqqoqfHx8lBFQNCCEwMfHR60SFYo26DOGAFBGQNEM9Z5QKNqmTxkChULRxRxZBTn7u3sWitOMMgRdiF6vJzExseEnNTWVVatW4eHh0bBt+vTp3HrrrSQmJhIbG4uTk1PDvm+++abR+ZYsWcK+ffu6bH6vvvoq0dHRCCHIy8tr2C6l5I477iA6OpqEhAS2b98OwMGDBxk+fDgJCQls2LABgLq6OqZPn05FRUWXzUvRQzHWw+KrYeWT3T0TxWmmzwSLewJOTk4kJSU12paamsqECRP46aefmo1PTU1lzpw5zY4xs2TJEubMmUNsbGyXzG/cuHHMmTOHyZMnN9r+888/k5ycTHJyMps2beJvf/sbmzZt4q233uKll14iMjKSO++8k2+//ZY33niDK6+8EmdnZ+svoug7ZO+CqmIoslqMquhDqBVBD2X9+vUsXbqUf/zjHyQmJnL48GGSkpIYM2YMCQkJnH/++RQWFgIwefJk7rzzThITE4mPj2fz5s1Wzzl06FCsaTT98MMPXH311QghGDNmDEVFRWRlZWEwGKioqKCiogKDwUBRURE//vgjV1999em8dEVP4ega7bHoePfOQ3Ha6ZMrgsd+3Mu+zJIuPWdssDuPnBfX6pjKykoSExMBiIqK4vvvvwdgzZo1DdsvvvhiHnzwwTZfb+zYscydO5c5c+Zw0UUXAZCQkMArr7zCpEmTePjhh3nsscd48cUXAaioqCApKYnVq1dz7bXXsmfPnnZfW0ZGBmFhYQ3PQ0NDycjI4NZbb+Xqq6+murqat956iyeeeIIHHngAnU7dP9gER1drj1XFUFkETp7dORvFaaRPGoLuwpprCGjRNdQRiouLKSoqYtIkrQ/5woULufjik73RL7/8cgAmTpxISUkJRUVFeHp6duo1w8PDWbVqFQApKSmkp6czaNAgrrrqKmpqanjiiScYMGBAp15D0UOpr4XjG8A1EMqytVWBMgRdyqs7XmWQzyCmhU/r7qn0TUPQ1p17X6RpmqQQghkzZnDixAlGjBjBu+++2+KxISEhpKWlNTxPT08nJCSk0ZgHH3yQJ598kpdffpnrr7+eyMhIHnjgAT777LOuvRBFzyAzCWrKYOT1sO5FzRAEJXT3rPoUn+3/jJGBI3uEIVBr/B6Mm5sbpaWlAHh4eODl5cWaNZrf9pNPPmlYHQB89dVXAKxduxYPDw88PDxYvnw5SUlJrRoBgLlz5/Lxxx8jpWTjxo14eHgQFBTUsP/PP/8kODiYmJgYKioq0Ol06HQ6lTnUlzn6p/aYuEB7VHGCLqW6vpqy2jLSStPaHnwG6JMrgr7CZZddxg033MDLL7/MN998w0cffcTNN99MRUUF/fr144MPPmgY6+joyNChQ6mtreX999+3er6XX36ZZ599luzsbBISEpg9ezbvvvsus2fPZtmyZURHR+Ps7NzovFJKnnzyyQZDc+ONN7JgwQLq6up44403Tu8fQNF9pK4B/zjwjQF7N2UIupjCKi3RI700HaM0ohPdfE8upez0DzATOAikAIus7HcAvjLt3wRENtkfDpQB97bn9YYPHy6bsm/fvmbbbIVJkybJLVu2dPc0eiy2/N44JWqrpHwiQMpl/9Sev3a2lJ9f3r1z6mPsydsj4z+Ml/Efxsvssuwz9rrAVmnlO7XTZkgIoQdeA2YBscDlQoimie/XAYVSymjgBeCZJvufB37u7FwUCkUXkL4V6iohcoL23DNcrQi6mILKgobfj5d2/9+2K9Yjo4AUKeURKWUN8CUwr8mYecBHpt+/AaYJU3RTCDEfOArs7YK52CSrVq1ixIgR3T0NRV8hdQ0gIHKc9twzXCsq01bvii6goOqkIUgvTe/GmWh0hSEIASwjHummbVbHSCnrgGLARwjhCtwHPNbWiwghbhRCbBVCbM3Nze2CaSsUCqscXaNlCDl5ac89w6G6BKqKunVafQmzIRCIPrMi6AyPAi9IKcvaGiilfFtKOUJKOcLPz+/0z0yhsEVqKyF9c4Nb6N3d7/KHLNf2KfdQl1FYVYiD3oFQt9AekTnUFVlDGUCYxfNQ0zZrY9KFEHaAB5APjAYuEkI8C3gCRiFElZTy1S6Yl0Kh6Chpm6C+BqImsjZjLS9tf4mzveOZAqZagiHdPcM+QX5VPt6O3oS7hXO8pPsNbFcYgi1AjBAiCu0L/zLgiiZjlgILgQ3ARcBKUwR7gnmAEOJRoEwZAYWiGzm6BoSeyuChPLlc05Q6WpWj7VMrgi6joKoAb0dvwtzC2JW7Cyllt/bO6LRryOTzvw1YDuwHFksp9wohHhdCzDUNew8tJpAC3A0s6uzr9kTS09OZN28eMTEx9O/fnzvvvJOamhqrYzMzMxs0hFpj9uzZFBUVndJ8Hn30UZ577jmr20NCQhpE6pYuXXpK5+9q/vWvf3X3FBRHV0PwUN48+BkZZRmMCx5HdkUOFY7uUKhUSLsKsyEIdw+ntLaUouqibp1Pl8QIpJTLpJQDpJT9pZRPmbY9LKVcavq9Skp5sZQyWko5Skp5xMo5HpVSNv/W6iVIKbnggguYP38+ycnJHDp0iLKyMqsCc3V1dQQHBzfrP2CNZcuWdVozyBp33XUXSUlJfP3111x77bUYjcZ2HVdfX9/lczFzKobgdM7H5qgug8ztHApN4OO9H3N+9PlcOOBCAFI9Q9SKoAuxXBEA3R4n6O5gcZ9h5cqVODo68te//hXQmtS88MILvP/++1RUVPDhhx8yd+5cpk6dyrRp00hNTSU+Ph7QlEMvueQSYmNjOf/88xk9ejRbt24FIDIykry8PFJTUxk0aBA33HADcXFxnHvuuVRWVgLwzjvvMHLkSIYMGcKFF17YIemHQYMGYWdnR15eHvPnz2f48OHExcXx9ttvN4xxdXXlnnvuYciQIWzYsIHHH3+ckSNHEh8fz4033mguCmTy5MncddddjBgxgkGDBrFlyxYuuOACYmJieOihhxrO9+mnnzJq1CgSExO56aabqK+vZ9GiRQ3qrQsWLGhxnLX5LFq0iNjYWBISErj33ntP9V+oOL4Ro7GOxypTcLN34+7hdxPlHgXAUVcvZQi6CCklBZUFeDtpMQLo/lqCvikx8fMiyN7dtecMHAyznm5x9969exk+fHijbe7u7oSHh5OSkgLA9u3b2bVrF97e3qSmpjaMe/311/Hy8mLfvn3s2bOnQbK6KcnJyXzxxRe88847XHLJJXz77bdceeWVXHDBBdxwww0APPTQQ7z33nvcfvvt7bqsTZs2odPp8PPz4/3338fb25vKykpGjhzJhRdeiI+PD+Xl5YwePZr//ve/AMTGxvLwww8DcNVVV/HTTz9x3nnnAWBvb8/WrVt56aWXmDdvHtu2bcPb25v+/ftz1113kZOTw1dffcW6deswGAzccsstfPbZZzz99NO8+uqrDeqt+/fvtzru6quvbjSf/Px8rrvuOg4cOIAQ4pTdaAogdTXfuHuwqzSVf43/F56OnjgbnNEJHUcdHKFot1ZLoPpAd4ry2nJqjDX4OPoQ4haCQDReEeQcgNpyCBne8km6mL5pCHoo55xzDt7e3s22r127ljvvvBOA+Ph4EhKsqzxGRUU1GInhw4c3GJM9e/bw0EMPUVRURFlZGTNmzGhzLi+88AKffvopbm5ufPXVVwghePnllxt6KKSlpZGcnIyPjw96vZ4LL7yw4dg//viDZ599loqKCgoKCoiLi2swBHPnamGhwYMHExcX1yBe169fP9LS0li7di3btm1j5MiRgNbDwd/fv9n8fv/99xbHWc7Hw8MDR0dHrrvuOubMmcOcOXPavHaFdXKPruJFb09GB45iTj/t72ivtyfUNZSj0gg1pVBZCM7N38OK9mOuIfB29MZB70CASwBpJSZDkLYFPjkfPELh1o1nbE590xC0cud+uoiNjW3m8y8pKeH48eNER0ezfft2XFxcOvUaDg4ODb/r9foG19A111zDkiVLGDJkCB9++GFDD4HWuOuuuxq5UVatWsVvv/3Ghg0bcHZ2ZvLkyVRVVQGaoJ1erwegqqqKW265ha1btxIWFsajjz7aMM5yjjqdrtF8dToddXV1SClZuHAh//73v1udX2vjLOdjZ2fH5s2b+f333/nmm2949dVXWblyZZvXr2hCVTHP1GVQ7eDKQ2MeapTBEuURxdH8g9qTouPKEHQSS0MAEOYWpq0I0rfCpxdoBrck84zOScUIuohp06ZRUVHBxx9/DGhBzHvuuYdrrrmmzf6+48aNY/HixQDs27eP3bs75tYqLS0lKCiI2traU+4PUFxcjJeXF87Ozhw4cICNG63fjZi/9H19fSkrK2tXwNuSadOm8c0335CTo6UkFhQUcOyYlo1iMBiora1tc5wlZWVlFBcXM3v2bF544QV27tzZofkoNFYnvcdyF2duiJhNpEdko31RHlEcq86nHlT/4i4gvyofOGkIwt3COV50RFsJOPvAiOugulgr7jtDKEPQRQgh+P777/n666+JiYlhwIABODo6tisT5pZbbiE3N5fY2Fgeeugh4uLi8PDwaPdrP/HEE4wePZpx48Zx1llnndL8Z86cSV1dHYMGDWLRokWMGTPG6jhPT09uuOEG4uPjmTFjRoPrpr3Exsby5JNPcu6555KQkMA555xDVlYWoElcJyQksGDBglbHWVJaWsqcOXNISEhg/PjxPP/88x2/eBunsq6SfyV/Sb/aOq4dc3+z/ZHukdQYa8m006uAcRfQdEUQKnUU1JZQ7uwF1/wEIcO0gaXZZ25S1iRJe/pPX5Ohrqurk5WVlVJKKVNSUmRkZKSsrq7u5ln1HXrze+NM8NqO12T8h/Fy84fTrO7flr1Nxn8YL//8b5SU/7v3DM+u7/Fm0psy/sN4WVNXI2XGdrn8hSgZ/2G83J/6hzbg0AopH3GX8tiGLn9tWpCh7psxgl5GRUUFU6ZMoba2Fiklr7/+Ovb29t09LYUNkFGWwft73mNmWTkj48+1OibKw5RC6ubDRLUi6DQFVQW42bthOLEXPp5PmIs7AGnUchaAqyl5ouzEGZuTMgQ9ADc3t4a6AYXiTPLfrf9FJ+GegiIItS5l7uXohaeDJ0d1QrmGuoCCqgJ8HH3g62vAwY2wSxfDz5ec1BxyC9QeS8+cIVAxAoXCRtmYtZEVx1ZwvWc8gfX1EJTY4tgojyiO6k2GQPUl6BQFVQV4G1yh8CiMuQVX/0F4O3qfrCVw9gWhh7IzFyNQhkChsEFqjbU8s/kZQlxDWFhh1HoOtJIWGuURRaqxEmrKoKKgxXGKtimoKsDbbEuDEwGLFFIAnU5zD6kVgUKhOJ18deArUopS+OfIf+KQvavV1QBAlHsUBfWVFOl0KoW0kxRUFeBdUw0ICNSKRxsZAgDXALUiUCgUp4/8ynxeT3qdscFjmeIzBApTIXhoq8eYA8apBjsVJ+gE9cZ6CqsK8a4oBL+B4OAKaLUE2eXZ1NSb1IrdAtWKoLfy1FNPERcXR0JCAomJiWzatKnT51yxYgXDhw9n8ODBDB8+vMWq2RdffLFDYnNtce211+Lv798gjGemoKCAc845h5iYGM455xwKCwsB+Pbbb4mLi2PChAnk52sFM4cPH+bSSy/tsjkpuoZXdrxCZV0l9426D5G9S9toclG0REPmkMGgDEEnKKouQiLxLs5qZHxD3UKRSNLLTP2L1Yqgd7JhwwZ++umnBmG53377jbCwsLYPbANfX19+/PFHdu/ezUcffcRVV11ldVxXG4JrrrmGX375pdn2p59+mmnTppGcnMy0adN4+mlNzuOVV15hy5Yt3HTTTXz++eeAJoD35JNPdtmcFJ1nb95evkv+jgWDFtDPox9kJWk72nANBbsGY9AZOOrkqgxBJzAXk3lVFjcyBOHumgppg+aQWyCU50F93RmZlzIEXURWVha+vr4N+jq+vr4EBwezcuVK5s+f3zBuxYoVnH/++YAmp/yPf/yDuLg4pk+fzubNm5k8eTL9+vVraBYzdOhQgoODAYiLi6OyspLq6upGr/3yyy+TmZnJlClTmDJlCgBffPEFgwcPJj4+nvvuu69hrKurK3fddRdxcXFMmzaN3Nxcq9czceJEqwJ5P/zwAwsXLgRg4cKFLFmyBNC0hKqrq6moqMBgMLBmzRoCAwOJiYnp6J9ScZowSiP/3vxvvB29uXnIzdrGzKQ2A8UAdjo7ItwjOOrkcmqGwGiEpM+hvrbjx/YhzIbAp76+kSFo1pfANQCQUJ5zRubVJ+sIntn8DAcKDnTpOc/yPov7Rt3X4v5zzz2Xxx9/nAEDBjB9+nQuvfRSJk2axJQpUxokJPz8/Pjggw+49tprASgvL2fq1Kn85z//4fzzz+ehhx5ixYoV7Nu3j4ULFzYoeZr59ttvGTZsWCMxN4A77riD559/nj/++ANfX18yMzO577772LZtG15eXpx77rksWbKE+fPnU15ezogRI3jhhRd4/PHHeeyxx3j11fZ3Bz1x4kSDomhgYCAnTmh+zPvvv5/p06cTHBzMp59+ysUXX8yXX37Z7vMqTj+f7/+cnbk7eWLcE7jaa75pMne0GR8wE+URRXLx8VMLFh9dBUv+pmnpDGhbHbev0iAvYQQCTrpdvRy8cDW4nuxL4BqgPZadAPfg0z4vtSLoIlxdXdm2bRtvv/02fn5+XHrppXz44YcIIbjqqqv49NNPKSoqYsOGDcyaNQvQtPtnzpwJaLLNkyZNwmAwMHjw4Eb9CkDrd3Dffffx1ltvtTmXLVu2MHnyZPz8/LCzs2PBggWsXr0a0O7czX77K6+8krVr157yNQshGlQqzznnHLZt28aPP/7IDz/8wOzZszl06BAXXXQRN9xwQ5e6rRQdJyknif9u/S+TwyYzt7/pBqOiQPtSb8MtZCbSPZI0WUvtqdQSnNinPZZbX4HaCg2GwLMf2J8UoxRCNM4cOsNFZX1yRdDanfvpRK/XM3nyZCZPnszgwYP56KOPuOaaa/jrX//Keeedh6OjIxdffDF2dtqf3WAwNHyRWso2myWbzaSnp3P++efz8ccf079//y6dsxCCtLS0hn4CN998MzfffHOL4wMCAsjKyiIoKIisrKxmvQTM3diWL1/OnDlz+O677/jmm2/47LPPGprnKM4shVWF3PvnvQS4BPDkuCfRCdP9X5ZJqbWNQLGZKI8o6pGkUUO/inxw8W3/JHL3a48V+e0/pg+SX5mPTko8goY12xfmFsbBQpPcd8OK4MwEjNWKoIs4ePAgycnJDc+TkpKIiIgAIDg4mODgYJ588smGVpbtpaioiL/85S88/fTTjBs3rsVxbm5ulJaWAjBq1Cj+/PNP8vLyqK+v54svvmDSpEkAGI3GBunozz//nPHjxxMWFkZSUhJJSUmtGgHQGs989NFHAHz00UfMmzev0f7//Oc/3HHHHRgMBiorKxFCoNPp1Iqgm6g31rNozSIKqwp5fvLzeDhYqNq2M1Bspp9HP8CcOdRB91CO2RDYdjFaQUkaXvVGdCHN3XFhbmFklGVQZ6w7aQjO0IpAGYIuoqysjIULFzb0zt23bx+PPvpow/4FCxYQFhbGoEGDOnTeV199lZSUFB5//HESExNJTExs0Oi35MYbb2TmzJlMmTKFoKAgnn76aaZMmcKQIUMYPnx4wxe2i4sLmzdvJj4+npUrVza0nGzK5Zdfztlnn83BgwcJDQ3lvffeA2DRokWsWLGCmJgYfvvtNxYtWtRwTGZmJps3b24Ijt9+++2MHDmSN998kyuuuKJD163oGt7e/TbrM9ezaPQiYn1iG+/M3AGeEe1uNGPuU9DhFFKjUWu/CDa/IigoPoa3sR6Cm68Iwt3DqTPWkV2eDXb24OR95lJIrUmS9vSf3ihDfeutt8p33323u6chXVxcunsKZ5ye/t44XazPWC8HfzhY3r/6fmk0GpsPeGGwlF9d1aFzTv1qinzglUgp17zQ/oMKjmqyyo+4S/nFFR16vb7Ggs8nyuveiJGyprLZvs1Zm2X8h/FyfcZ6bcNrY6T8/PIufX1akKFWK4IzwPDhw9m1axdXXnlld09FYSNkl2dz3+r76O/Zv1nrSaDDgWIzUZ79OOrg1LEVgdktZHCx+RVBYU2pJjhncGy2z2oK6RlaEfTJYHFPY9u2bd09hQbKysq6ewqK00ytsZZ//PkPquqr+O/k/+JssNIqtYOBYjOR7pH8z7AJWXgM0fZwjRxTxlDYqDPei7dHISUFxhp8XKwXmvo7+2Ovs2+cOZSXbHVsV9MlKwIhxEwhxEEhRIoQYpGV/Q5CiK9M+zcJISJN288RQmwTQuw2PU7tzDykksdVNMHW3hO19bU8uPZBknKTeGzsYw0B3mZk7tAeO7oi8IiiTEBeSUdWBAfAIwy8Im16RVCdn0yZTuDtEWF1v07oCHMLO9mXwDVAqyM4A+/hThsCIYQeeA2YBcQClwshmkSluA4olFJGAy8Az5i25wHnSSkHAwuBT051Ho6OjuTn59vcB1/RMlJK8vPzcXRsvgzvi1TUVnDbytv4+ejP/H3Y35kVNavlwVlJHQoUm2nQHKrIbv8XVM5+8B+kvVZlgRY8tkEK09YD4O0zsMUxYW5hpJVZrAiMtVBZeNrn1hWuoVFAipTyCIAQ4ktgHrDPYsw84FHT798ArwohhJRyh8WYvYCTEMJBStlYQ6EdhIaGkp6e3qJkgsI2cXR0JDQ0tLuncdopqCrg1t9uZV/BPh4f+zjnx5zf+gGZSR12C4FFCqnOyKjyPHD1a/2A+jrIOwj9p2hVxdII1cXg5NXh1+7t5GdqLmJv/7gWx4S5h7EpexNSSoS5ZWVpdocNdkfpCkMQAlgIaZMOjG5pjJSyTghRDPigrQjMXAhsb8kICCFuBG4ECA8Pb7bfYDAQFRV1ipegUPReMssyuWnFTWSVZ/Hi5BeZEj6l9QPMgeLh13T4tfyd/XHS2Z+sJWjLEBQcgfoa8I8Fc8C6osAmDUFBnnZv7O0S0OKYMLcwKusqyavMw8/VVF1clg0BTZ0sXUuPyBoSQsShuYtuammMlPJtKeUIKeUIP7823nwKhY2QXJjMVcuuIr8qn7fPebttIwAnC8naqTFkiU7oiHQN4ajBrn1FZeZAsf8gLS8ebLOozGikoDAVAG/Hlu/uw920m9zjpcfPqMxEVxiCDMAyDB5q2mZ1jBDCDvAA8k3PQ4HvgaullIe7YD4KhU2QlJPEwl80JdgPZ37IsIDmRUpWyUzSHoOGnNLrRnnFcNS+nUVlOfsBoTVhcfbRttliwLjwKAUmZ4ePo0+LwxqlkJ5BmYmuMARbgBghRJQQwh64DFjaZMxStGAwwEXASimlFEJ4Av8DFkkp13XBXBQKm0BKySPrH8Hd3p1PZn/CAK8B7T/4FAPFZqK8Ysiys6Oi8Gjbg3P3g3c/MDiBs8kdVGmDK4LMHRTo9Djq7HGyc2pxWJBrEHqh1zKHHFzB3rV3rAiklHXAbcByYD+wWEq5VwjxuBDCrKP8HuAjhEgB7gbMKaa3AdHAw0KIJNOPPwqFolU2Z2/mSPER/jbkbwS7dlCm+BQDxWbMmUPHitqxgDdnDIFtrwgyd1BgZ8Dbyad5cZ8FBp2BIJcg0kvPbKeyLikok1IuA5Y12fawxe9VwMVWjnsSUC2sFIoO8uWBL/F08GRm1MyOHWgOFI/omPihJQ0ppCXHaVU5q7YK8g9DrEmY0MEddHa2GSPITCLf2QPvVtxCZsLdw0kuStYyh85Q7+IeESxWKBTtJ7s8mz/S/uD8mPNx0Du0fYAlHVQctUaEewQCOFpbDLmHWh6Ynwyy/uSKQAgtYGxrKwKjEbKSKDA44u3UtjtuathUUopS2Hpi68mistOMbRmCVc/A1g+6exYKRaf4+tDXGKWRSwZc0vGDOxkoBnDQOxDiHEiqwQ4O/q/lgWaNIX+L1EdnH9szBPkpUFNGgU62mjFkZl70PLwdvXl/z/ta5tAZMAS2pTV04Cet7VsnlsUKRXdSW1/Lt4e+ZWLoRELdTqFQroOB4nfXHGFfVglBHo4EejgR5O5IoIcjoe79OVyWCwf+B+Pvsn5wzj7QGcDbopmSs/cZqZTtUWTuQAIFdZXtMgSOdo4sGLSAV3a8wsHQ+QysKYPqMi14fJqwLUPg4gvleW2PUyh6EhUFYO8Cdg6sOLaC/Kp8Lh146amdK3OHVS18axRX1PLMLwdwtNNTWVtPnfGkpIS9nwOOPvWUZ2zFpTT7ZM67JTkHwDdG09Y34+x9xoTUegyZOyizd6FW1rXLEABcOvBS3tv9Hh+UJfM0aKsCZQi6CBc/LXjVhJKqWsqr6wjyaDmtS6HoFqSEtyeB3gEu/5IvD35JmFsY40Ja7lbXIhUFWu7/iGvbNfy3/SeorZcsvmkUCaGe5JdVk1VcRVZxFSuOlvFrwUp2Odhz9sFl1s+Zsw9Chjfe5uRte8HizB0UBAwCctptCDwcPLhowEV8tu9TbrfTE1KaDT5d26bWEtuKEbj4NVsRHM0rZ9aLa7jg9fVKsE7R8yjJ0L6885M5+MF0duTs4NKBl57sO9wRjq7WHttZUbxsdxbBHo4khnmi1wn83R0ZEubJzPhAHpvxF0Dwh6MvZTt/aH5wdZmWneTfRBrB2UerI7CVz5qxHrJ3UeCraTS1VkzWlKtir0IIwcfu7qc9hdS2DIGzD9SWQ43WP3dvZjEXv7mezOJKsoqrSM5RWv2KHkb2bu3xgnf4wtsbB6NkfkFOx79IjUZY/Rx4RUHE+DaHl1TVsiY5j1mDg6zmvbvauxLtOYB1jh44pK2lrqKo8YBcUxN2/yYJps7eYKyD6pKOzb+3UpIBtRUUuGvlUe3JGjIT6BLI7PBz+M7NhcKi1NM0QQ3bMgQuJo2iijy2phZw2dsbsdfr+OCakQCsT1Hxg55AZlFld0+h55C1CxCURI1nmYOe2QYfPH5/Er6/WcvTby/7l8KJ3TB5Eejb9giv3J9DTb2R2YOt+P5NjAwcxgnnGqCOVT993ninpcaQJbZWVFZVDEC+yZZ6OXRMbO/aITdRpdPxZc7Grp5ZI2zSEGzbd4gr39uEn6sDX/9tLJMH+hPq5cSGIzby5uzBbE0tYOzTK9mSamN+5JbI3gXe/fgh7Xcq66u4bMbrMPkB2PUlfDgbSrLaPoexHlb9G3wHwOBmdZ1WWbY7i0B3R4aGtfzFNcx/GNWyhu1O3lTt+ZEjuRYr6pz9YOekNaOxpMEQ2EjmkMkQFFAPtC44Z43+XtFMrpF8XpZCRW1Fl0/PjI0ZAl8A3ly2kf5+riy++WxCPLUA8dn9fNh4pACj0UZ8lz2UFfu1nOnNR5UhACB7F8bAwXx18CsS/BKI9YuDyffBpZ9qWTkfzm74smmRPd9B7gFtNaDTt/mSZdV1rDqUy8z4QHS6luUQEv0TAdgbnsBk3Q4e/Gbryc9P7n5NaK7p6zUokNrITVeV5gIrMFbjZu+GQW/o8CmuFV4UyTq+T/m+q2fXgE0Zgh+SawBI9K7nixvH4Ot6sipzbLQPxZW17MuyEd9lD2X1Ic09tzu9jS83W6CyEIqOs9HDh2Mlx7hs4GUn9w06D678BgqPwdLbW44Z1NdpqwH/OIhto1mNiZUHcqipMzJ7cFCr4wJdAglxDWGPqwuuVGJIW8+nm0zS1JYaQ5Y425ohMK0I6iqbBYrTCioorqxt8xRDXcMZWq/j470fU2tse/ypYDOGoKbOyIc7ywG4cbg77o6NLfPZ/bTVwobDNvIG7YHklFaxP6sEnYDdGcoQkL0HgC+qs/B29GZG5IzG+yPGwvRHYN8PsPlt6+fYvRgKDsOU+0HXvo/7z7uz8HNzYHhE2/7sof5D2V6RgdHgwkKvvTzz8wEysjKgNKt1Q2ArCqSmoHhBXXkjt1C9UXL+6+t44PvdbZ/D1Z9rS8rJLM9keery0zJNmzEE9nY63r9hEtLOCUNV86BwoIcj/XxdVJygG1ljWg2cNySYjKJK8ss63LG0b5G9i2SDgT8L93JhzIXY6+2bjxl7BwyYBcsfhPStjffV18Kfz0BgApw1p10vWVFTxx8Hc5gZF4i+FbeQmaH+Q8mvKiC9/wQmswUw8v73P2s7m6aOAjh4gNDb3oqgpqSRIUhKKyKvrIYVe09QXNHGXb5rIBOLcunv0Y8P9nxwWtLcbcYQAHi52CNc/Fp8E47p78PmowXU1dtmc+3uZk1yLj4u9lw6QmvOYfOrgqxdvOXrj5OdE1fFXmV9jBBw/hvgHgRfX9O4WCvpMyhMhSkPnmwT2QarDuZSVdu2W8jM8ACtYGx7QDT68hM8NbKW6gxtJWN1RaDTaW0qbaWorKoYDM4UVBU2MgR/HswBoKbeyE+7M1s/h1sAOuCv/eZTa6wlr7LrsxttyhAAJpkJ6w3ux/b3oay6Tn0BdQNGo2RNch7jY3wZHOoBqDhB8okkfnXUc8WgK/BybMVN4+QFF3+kyRB8f7NWM1BXDX/+B0JGwIAZLR/bhGW7s/BxsWdUVPuyW6I8ovBw8GCHvh50dpyr38pAXTrVehdwD7F+kC0Jz1UVU+foQVF1UaMaglWHchke4UWMvyvfbW/a0LEJpt7Fc7ziWDJvCX7OXd+qVxkCC8b004I561Wc4IyzL6uE/PIaJsb44eZooJ+fC7ts2SDXVvGWzMNJ2LEwdmHb40OGwYx/QfJyWP8SbP8YStJhygPtXg1U1daz8kAOM+Lb5xYCrYfxUL+hbM/fC5HjcT7yC8OcskkhvOXXtSXhuapiihzdkJxUHs0rq2ZXejGTB/hxwbBQth0r5Fh+ecvncNNaVurLck6torwd2KAh8INy61/0vq4ODAxwY6OKE5xxVidrxnlCjBa0TwjxYI8NG4Lkoyv41dmJBQFj8XT0bN9BI6+H+Avh9yfgj6cg/GzoP7Xdr7nqYC4VNfXMjm+fW8jM0IChpJakUhA9FfIOcVbtAXZWB3I0r4UvNxtbERQ4uAAnawhWH9Le65MH+jN/aDBC0PqqwLQiOJ0yEzZoCEwrghYCLmf392FLagHVdfVneGK2zepDuZwV6Ia/uyMA8SEeZBVXkVPagerZPsSbez/ESUquTri+/QcJAee9BN5R2h13B2IDAD/vycLL2cCYfh0rehrmr6mZ7vDSDIhe1nJIhrF8bwtfXM42JDxXXUKhg1arZDYEfxzMxdfVnrhgd4I8nBjb34fvd2S0HAR28QMElOWctmnaniFw9oX6aqgutbr77P4+VNUa2Zlmu3ejZ5ry6jq2HStk0oCTvs+EUE8Am1wVJBcm82vJIRaUV+MZ0MEGMg5ucOW3cME7EDWh3YdV1dbz+/4cZsQFYqfv2NdCrE8s9jp7dpQdbxC0q/U5i1/2tGAIzF3KbEF4rqqYAoOW7eXj6EO9UbImOZeJA/waivXOHxrK8YIKth1rwV2mt9OMQalaEXQdFnpD1hgT5YMQsP6w0h06U2w8kk9tvWSihSGIC3ZHCNidbnsFfm/ufBMXKbjaOarduf+N8IqEhI51L1ubnEdZdR2z2pktZIm93p5433h25OzQ+hPr7OgXN4qktCKyi62s6Jx9wFgLNTYg8lhVTIFJ28nb0ZuktCKKKmqZPNC/YcjM+ECcDHq+29GKe8jt9LastF1D0EKDGg9nA3HB7qqwrAuoN0qW7Mhg6c7W0+NWH8rFyaBnROTJzBgXBzv6+7myO6PoNM+yZ3Go8BC/HvuVK0rL8QxMPGOvu2xPFh5OBsb2b79MsiXDAoaxL38flSOvg5vXMmmoljr66z4rd7G2Ul0sJVSVkK/XoRd63B3c+fNgDjoBE02xMABXBztmxgfy085MqmpbcEm7BqgVQZfiYnqjt5A5BJru0I7jRS3/UxStIqXklz3ZzHxxNX//Kom/f7mj1VTQ1cl5jOnnjYNdY12ahBAPdtlYCumbO9/Exc6JqwsLtEKw00RVbT1JaUV8uvEY93+3m593Z3NubACGDrqFzAz1H0qdrGN3wQHwH0S0vyvR/q7W3UO2okBaWwnGWgow4uXohU7oWHUol8QwTzydGxcHnj80hJKqOlYeaCEO4Hp6exfboCEwrwhaNgRj+/tSU29s2WensIqUmv9z3mvruPnTbRil5IVLh+Dj6sCi73ZZLdRLK6jgaF45E2Ka50YPDvUgp7SaEyW9L2CclFbEa3+kdKgK9FDhIVYcW8EVviPwNBohqGsNQU5JFf/8ZifnvvAncY8sZ/5r63hoyR6W7c5ieIQXt0yJPuVzD/EbgkCwPWd7w7YZcQFsOlpAYXlN48ENwnN9/PNllpdAa1HZkDZq4RYyMy7aF383h5azh9wCtGCx8fTcnNpWq0rQgsXQau/ikVHe6HWC9YfzGBft2+I4xUn2Zhbz5E/72XAknxBPJ569KIELhoZgp9dhr9dz6+fb+WBdKjdM7NfoOHPaqDk+sCNnB6/ueJXHxz3O4JCThWUBsY5n9oI6yet/pPDrvhP4uTlwialSui3e3PkmLgYXFuIBOjvwO6vL5lNQXsOCdzeRVljB2P6+zIwLJDbYg7hgd0K9nKw2n+kIHg4eRHtFa3ECEzPjgnjtj8P8tv8EF1v+DWxlRWCWlzDW4O3o35A2OsWKIdDrBOcPDeG9tUfJL6vGx0IQE9BWBLJe+5u5Nj++s3TJikAIMVMIcVAIkSKEWGRlv4MQ4ivT/k1CiEiLffebth8UQrS/BPJUMTiCg3urhsDVwY6EUA8VJ+gAN3+6jYMnSnnkvFhW3juJS0aENWSfzB4cyLSz/Hl+xSHSCkya6ru/gaeCiF5zF3Pdkunv68TmrM3ctOImNmdv5rvk74gNdkcn4OCxNNjxGXxzLWRs68arbB919caG984TP+5rV6OdjLIMbTVw1hV45BwEv0Fg59Dmce2hpKqWq9/fxPGCCj64ZhTvXzOSu88dyMz4QMK8nTttBMwM8x9GUk4SdcY6AOJD3AnxdGqeRmorwnNmQ1BfibejN6ss0katcf6wEOqMkp92WekxYSoqqypsQ47iFOm0IRBC6IHXgFlALHC5EKKp2tR1QKGUMhp4AXjGdGwscBkQB8wEXjed7/Ti7NOqawi0OMHO9GLKqutO+3R6O2XVdaQVVHLd+Cj+Oi6qma9fCMHj8+MRAv7vhz2au2T/UqTQM6h0Iy/XPsK61xO5ZcWNhDj5M9h3ML8e/RmnvV/xhcvz3LRpBvxwC+z5FnZ+2U1X2X52phdRWl3HollnUS8l9327q00X0ep0rZ/w3P7nac1ousgtVFFTx7UfbOFgdilvXjmcs08xGNwehvoPpaKuguTCZED7v8+IC2S1KSOpAUdPEDobWBGYXEO15Xg5eLO6SdpoU84KdCc2yJ3vtqc32i6lZE+JVovwjw9+PS2xy65YEYwCUqSUR6SUNcCXwLwmY+YBH5l+/waYJrTbkHnAl1LKainlUSDFdL7Ti4tfi+mjZsb296XeKFWnrHZg7kzV38+1xTEhnk7cc+5AVh3M5aedmXBsPflh0xlZ/RrvDvkbd7hBVFUl7+9ZzwVZh0ktTePgz3cSI9L4XMxGXv87hI6EE3vP1GWdMqsP5SEEXDYyjAdmD2JNch6fbTre6jFr0tcQ5hZGhHDUblICB3d6HlW19dz48Ta2Hy/kpcuGMuWsrncpWGIuLGsaJ6ipM/LnQYsbL1sRnqsqokoIyuurqK5xbpY2ao0LhoWwM72YlJwyKmrq+HzTcWa9tIabf9BiBzMiBNV1XS+K2RWGIARIs3iebtpmdYyUsg4oBnzaeSwAQogbhRBbhRBbc3Nbv5tvExe/Vl1DAMMjvDDohXIPtYMjuZqUQH8/l1bHXTM2koRQDz768Vcoz2U7sRjdD/Bq6XLO8h3Mu/O+w2vCP5iGK3oEy8dez4+Tl/Nw5WVku8VBQDyc2NPjC5HWJOeSEKplhiwYHc6EGF/+tWw/x/OttxqsqqtiS/YWxoeMR5ib1XcyY6i23shtn+9gbUoez140pN1qop0hyDWIQJfARnGCEZHe+LjY80tT95C5qKwvU1VMkakOJDNf1yxt1BpzE4PRCbh7cRJj/vU7D3y/GyEEd84bD8CcKIGHU8e7nLVFr8kaklK+LaUcIaUc4efXSfU9l7ZdQ072eoaGeylD0A4O55ahExDu49zqOL1O8K/zB3NW9S4A3igrxTH4C4b4JfD2OW/jERAHU+7H6/rfGR18NssLdhFvUiLdlV4MAXGa37WkDbXGbqS4spaktKKGD7wQgmcuTEAvBP/4ZqfVVqhbT2ylqr6KCSETIHuntjEw/pTnUG+U3LN4J7/tP8Hj8+K4aHjoKZ+rowz1H8qOEzsaXGF6neDcuABW7j/R2KXh7NP3YwTVJZSYDEFKdr3VtNGm+Ls5Mm1QAHszS5gwwI/FN53NsjvGc/GYGHD0OG0ppF1hCDIAy7SIUNM2q2OEEHaAB5DfzmO7jHd2vcPSw0upd/bV7kaMrS+xzu7nw57MYtUgpQ2O5JYT7u3cLDZgjfgQDy73T+MTFz+SnX4g2DGeN6a/gat9Y7fSzMiZpJWmoXPMQK8TWh1CgOnL8cS+03EZXcKGw/kYJY3SYYM9nfi/82LZdLSAD9enNjtmbcZaHPQOjAwcCdm7tcpgR49TnsOrK1NYujOTf84cyNVnR57yeU6F0YGjyanMISk3qWHbjLhAymvqG1fr24LeUFUxZXba3fuxXGObbiEzL12WyJYHp/PaFcMYFeV9Mph/GovKusIQbAFihBBRQgh7tODv0iZjlgJmLd2LgJVSu2VYClxmyiqKAmKAzV0wp2bUG+tZlb6KB9c+yEW5K1npaEC2IYU7e3AQUsKSpNMTqe8rHM4to18r8YFGSEkWe/iPnxP15f15bPTzOBuarySmhk/FTtjxR/oKYvxdtR4RAaYchBN7unD2Xcua5Fxc7PUMDfdstP3i4aFMO8ufZ5cfaIipNByTvoaRgSNxtHOErF2dcgulF1bw+qoU5iQEccvkU68LOFVmRc3C08GT93a/17BtbH9f3BzsWL7H4m7W2RZcQyWUOmifC2O9I5MHts+T4Wxvh7eLlZWD6+mTmei0ITD5/G8DlgP7gcVSyr1CiMeFEHNNw94DfIQQKcDdwCLTsXuBxcA+4BfgVinlaamY0Ov0fDLrE56b9Bx1QnBngB9X/nYjW7K3tHjMwEA3hoR68PXWtNPSHq4vUG+UHM0rbzM+YGbjoe/5p7sdA+z9Odd3ESMjAqyO83DwYEzwGH5N/ZXBIe7szihGOriDR1iPDhivSc7j7P4+zSp0hRD8+4LBONjpuefrndSbXETHSo5xvPQ440PGa1kmhUcbGQIpJU//fIBlu62kFFrhX8v2IwQ8MNtKd7AzgLPBmQWDFvBn+p8cKjwEaG1ipw7yZ8X+EyeLCp19tBVBX/5cVRVTaq9l+3g6uhEffOqrPADcAnv0igAp5TIp5QApZX8p5VOmbQ9LKZeafq+SUl4spYyWUo6SUh6xOPYp03EDpZQ/d8V8WkIndMyInMH3Ix7i0dx8sityuHb5tdz8280NKW9NuXhEGAeyS1XXshbILKqkus7YrhXB7tzd3LH5SSJqa3lv0jO8dOnoVhugzIicQUZZBn6+ORSU15BRVKnFCXqoITiWX87xggqrVdIA/u6OPDY3jh3Hi1i8VcuRWJuxFkCLD5hXOhapo7/vz+HNPw/z96+S2JvZ+ntw/eE8lu3O5tbJ0QR7OnXBFZ0al591Oc52zo1WBTPjAikor2H78SJtg5O3pgJc00pDlt6OhSEYGxnaYtpouzGvCFTP4q7BzjWQC8vK+d/gO7ln+D3szt3Ndcuvo6quuZTBeUOCcbDTNXxwbZraKvj1oUZfxIfbkToKcLjoMH/7/W94Sx1vF9fhETy8zZebGj4VO50deVJbte3JMAWM85O1Vow9jDXJmg98QiuZIfMSgxkV6c1/fz1IaVUtazLWEOEeQbh7uOYWgobU0bp6I//+eT+RPs54ORu47fMdLda11NUbeWzpPkK9nJpVb59pPBw8uGTgJfyS+gtppdrnxtz6cld6kTbIXF3clwPG1SUU6rQYwdio9lWXt4pbIEhjixL6ncEmDQEu2gfVsbKIa+Kv4cUpL1JYXcgvqb80G+rhZGBWfCA/JLWiDGgrrPg/WP8KfHF5Q9XkYVPqaL9WXEMZZRnc+OuNGHQG3imswi9sbLsaprjbuzMueBzb81dhp7PIHDLWQd6hrrmmLmRNci4hnk5E+bb8txBC8NCcQeSV1fDSyn1sydqirQZACxQ7+4Kblur51dY0DueWc//sQbx02VCO5Zfz4Pe7rbopP998nIMnSnnoL4NwNJz+msy2uCr2KvRCz4d7PgTAx9WBQHfHk/0lbEGBtKqYQqFHGu2I9LFeTdwhRt8MD+WAYxecqwm2aQjMdyOmWoIRASOI9ozm8/2fW/2QXTIijNKqupY7LtkCB3+GzW/DgJlQnA5LbwcpOZJbhoeTAR9rwS0grzKPG3+9kcr6St4a/ShhhWkQOb7dLzsjcgYnKrKJDMnT3HP+cdqOHuYeqqs3sv5wPhNifFuXbMjaRcKSc1jq9wYndv6bGmMNEwJHa/uyd2puISEoq67jhRWHGBnpxbmxAYzp58Pfpw/gh6RMvtrSeHVaWF7Df389xLhoH2bEBZ7Gq2w//s7+zO0/lyUpS8ir1D5nccHu7M009Zdo0BvqwyuCqmIK0SGNjgR6dIFWlt7QoY5zHcE2DYHeoFU2mgyBEILLBl7G/oL97Mrb1Wz4mH4+hHk72a57qCQLltyiuSwu+RimPQz7foCt75syhlysfvmty1jHZT9dRm5lLq9Pe50BZp2UiHHtfukpYVOw19nj7LWHXenFSJ/+oLfvcZlDO9OLKa2qazE+0MCur6DgKLG6NAJdN+JkNDL8w4vgnWmQs7/BLfT2n4fJK6vhgdmDGv62t06JZly0D48s3cvB7JPugf+uOEhZdR2PnBfXZbpBXcG18ddSJ+v4eN/HAMSFeHA4t4zKmnoLBdK+bAhKKAJkvRNBHt0Xs2kPtmkIQFuCWxSVndf/PFwNrnxx4ItmQ3U6wcXDw1iXkn9SNM1WMBphyc2atvqF72tCaGPvgOjp8Mv96HP2NosPlNWU8ej6R7n5t5txMbjw/oz3SfRPhGNrNQPs31SKqmVc7V0ZFzKOPLmF4spq0otrNVXOHrYiWJOcixAwLroNLZ+U3yByPPq/J7HMsx8OFSEUxF6rGTcHN4iezomSKt5Zc5Q5CUEMDT/ZrEevE7x46VDcHA3c+vl2Kmrq2JdZwuebjnPVmAgGBLid5qvsGOHu4ZwbcS6LDy6mpKaEuGB3jBL2Z5f0/RhBfS3UllMsJXqccLLvfndda9iuIWgiM+FscGZe9DyWpy5vWMpacuHwUISAb7alN9vXp1n/MhxZBbOeBr8B2jadDs5/C6OTF4/XPMdAL4vhmes5f+n5fJ/yPdfGX8vi8xYT72sqBEtdB+FjO9x+cUbkDErr8tE7HTfFCeJPS1FZWkEFV7+/udHddntZk5xHQohH65WjRWmQewCip5NakkqJMZfKunHcmDUX4zXL4L5UiJrI878eos5o5J8zmstQ+7k58NJliRzOLeP/luzlsR/34uFk4K7pAzo85zPBdYOvo7y2nK8OfNWgurk3swScPAHRd2MEpoBuiazHQde+1OruxIYNgW8z4blLB15KnbGObw9922x4iKcT46N9+WZbulWZgD5JxjZY+QQMmgvDFjbe5+LLkYkvESmy+cvx/1BWXcpjGx7jphU34WTnxMezPuau4XfhoDdJKZdkajnyEWM7PI3JYZNx0Dtg77mb7ccLtYBxWXabelEdwWjUVEJXH8rlxd86FoguqdJkJdp0C6X8pj3GnMOa9DUA3DLmL+zOKOZ7U7/aA9klLN6WxsKzI1uU7BgX7cvtU6L5dns6m44WcO+MgXg4d73+TFdwlvdZjA8Zz6f7P8XbFTydDezLLAadXjMGfdUQVBUBUE49znbKEPRcXHyb6Q1FeUQxNngsiw8tptZY2+yQS0aEkVFUyTpbaGxfXQrfXq81xJj7crMglZSS3+vduMl1HP+u2sA5iyfzXfJ3/DXuryyes5ghfkMany91nfYY2f74gBkXgwsTQibg6LGHTUfzLCqMu8499Pnm46w/nM9ZgW78sjebY/ntz2/fcDifeqNsNW0U0AyBRxj4DmBtxlqiPKK4ZuRwhoR68OzyA1TU1PHvZQdwc7DjtqmtVwXfOX0Akwb4MSLCi8tGhrd7rt3B9YOvp6CqgCUpS4gLdmdPhkXAuK/GCExZdZXU4mbfs1x21rBhQ+CnvQmbtH67bOBl5FTk8MfxP5odck5sAB5OBhZvtQH30LJ/QmEqXPC25tc38fux31m0ZhFTv57Kq4duZpP/cQ47uzOzpJhPxjzJ3SPu1qQSmnJsrdYQ6BTlE2ZEzqBOFHOgcCdlngO1jV1kCNIKKvj3sv2Mj/blo2tHYacTvLf2aLuPX5Oci7NJpLBF6mo0F1v0dCrqKtl6YisTQiag0wn+b04sJ0qqufnT7fx5KJfbp8a0KU6m1wk+/OtIvrrp7FaL8noCwwOGM9R/KB/u/ZBBQS4czC6ltt7YtxVITb0IanW1eDp0fbpnV2PbhgDZ7I5kYuhEgl2CrQaNHQ165icGs3xvNkUVNc329xmSPoedn8OEexvdwa/LWMffV/2dDZkbGBk4khjdX/HKf5RlF/7MIxWQsPwxqCyyfs7UdRA+RnMJnAITQyfiqHfGzmsdW/IM2v8vp/OGQJoaxwghePrCwQS4OzI/MYTFW9Oa99ptgbXJeZzdzwd7u1Y+TmmboKYMoqezOXsztcZaTVYCTar5LwlBrD6US6iXE1ePjWjX6woherwRMHNd/HVklWeByx5q6o2k5JT1bQXSqmJqAamrx8e5k9ISZwDbNQQNtQSN3UN6nZ5Lz7qUrSe2WpWduHhEGDV1Rpbu7EVCdL89Cp9domX+tEXGNvjx7xA5ASbd17C5zljHc1ufI8wtjBUXreDZic9SnjeCGO9wreLxko+1GMC31zVvsF2Wo1UDdyBttCnOBmeuGnQ1Bve9/HxoS5dJTXy2SXMJPTB7EKFemk/+hon9qKo18unGY20efzy/gtT8ina4hVaAzgD9JrEmfQ1Odk4MDzhZXb1o5ln093Ph0fPi2qXi2tsYHzKeAOcAUipWAaaAcV9WIK0qptSUFOHv6tm9c2kHtmsIXEyBPSt9CS6IvgAHvQNfHmjeFjE+RGv43atqCo6ugeTlsPhqzUXREmU58NVVmqbJxR+C3q5h1/cp35NSlMLdw+/GXm+vic3ll9Pf35Q6GjEWZj+n+cF/e6TxeY+Z4gOdMAQA1w5eiE668GfOx1rmUM7+5kanA1i6hC4fdVICYECAG5MH+vHRhtQ2q8nXpGjvnwkD2goU/w7hY5D2rqzNWMuYoDHY60+6f8K8nfn9nslMj7Uuwtfb0ev0nNf/PJLyNuHkWK5VGPdlQ1Bd0mAIgt1acRn2EJQhsNKy0tPRk1lRs/jxyI+U1JQ023/JiDD2ZJScLJfv6VTkaUHf5F/h+5usf3nW18LihdoH87JPG2Q4QKsLeHXHqwzzH8a08GkAZBRWUlNnpJ+lnMKIv8LIGzQZCsvewqnrwOACwYmdugxXe1cS3S6kwm4f6x2doa4KCo60fWBTjEZk/hEWfacVDz594eBmhVg3TuxHXlkNS3a03B7DaJT8b1cWwR6Ojf8OTSnJ1ArgoqdzpPgImeWZDW4hW2Ju/7nUy3oCg/exL7NEixHUVUJNH6zNqSqmzGQIQjyUIei5mL/oWkhBvPysy6msq2RpStPWCjA/MQQ3Bzte/t26YmmPo6IA4ubD9Mdg73fwv7ubKxj+cj8cXw9zX4Ggxhk/7+15j4KqAv458p8NX5iH80xic/5NxOZm/ltzKy29A9K3aduOrYOwUVpFdye5IvYyjLXu/PfEZiScmnto81vIV0eQkpLMA3856RKy5Ox+PsSHuPPOmiNW04WllDy8dA/rD+dz/YR+rVf0pvyuPcacw9bsrdr5g8/u+Lx7OVEeUST4JlDjtJl9WcUYnfpwUVlVCXl22vvK19mze+fSDmzXEDh5gdC12LIy1ieWIX5D+PLglxhl405mHs4GbpjYj1/3nWBnWtEZmGwnqKuG6hKtknr832H83bDtQy1uYGbHp7DlHTj7Nki4uNHhmWWZfLz3Y87rdx5xvnEN2w/naIag2Z2w3gAXf6TFDb68Qvuiztl3Smmj1hgbFUht/jQOVR5hjbNzxw2BlNRuehedrOfikHyuGGU99VIIwQ0T+nE4t5yVB3Ka7f/vr4f4dONxbprUj2vHR7X+mikrwC0Y/GPZV7APTwdPQl3PXPvInsTc/nMpMaZRwXFyjab3Tl/MHKoqJl+nZc+5GtrZtKkbsV1DoNNrAeNWehdfOehKjpUc45ejzVVJ/zouEi9nA/9d0b7io6+2HOfndjYX6VLMHzKz2uO0h2HEdbDuRVjzPKRvhZ/ugqhJ2oqhCS9ufxEhBHcMu6PR9iN55Xg6G6x3UnLxgcu/1LJkPvyLti2ia1whbo4GBjhPw2D05RVfP4zZHdQcOrYeQ2EKANcPqGz1Tn724CBCPJ14e01j99M7q4/w6h8pXD4qjEUzm1f/NqK+Dg6vguhpIAR78/YS6xPbozSBziQzo2ZiJwwYPLdzuMz03umjhiBXpxVTutur9NGeTROZiaacG3kuA7wG8MqOV6itb1xg5uZo4G+T+7P6UC6bj7a+tN14JJ9F3+3mpS5yJeWXVbe/Y5r5Q2Z2hQmhBXUHXwy/PwafXKDdvTcJDgPsyt3Fz0d/ZmHcQgJdGqtaHs4po5+vdbE5QCv6uuBtqCwEO0cIGdaBK2ydMVF+VORM54Be8mthxwxB5cb3KJHOFBv88Cxp3Ygb9Dr+Oi6SzUcLSDKt/BZvSeOpZfv5y+AgnpzfPLbQjPQtUF0M0dOpqqsipSiFOJ+41o/pw3g4eDApbBIG9yR2F5n+dn0xYFxdQj6aK7RpP+6eiG0bAmefVg2BTui4c9idpJel813yd832XzUmEn83B55bfrDFL+biylruWbwTKSE5p6zTPQ0OnShl9L9+Z/nedvYuNV+fs0V6o04H89+AgbM1bf/LPj+5YjAhpeQ/W/6Dr5Mv18Vf1+y0R/LK22xGw1l/gb/8Fybco4nVdRGj+/lQVZhAhM6d1+xrqWuj93QDFQUYDv7ID8bx2IcNa5db6bJR4bg52vHOmiP8vDuLRd/tYkKMLy9cmti+HP6U30Dood9kDhUeol7WE+vTftG9vsj50fMRduWsLDAZ4j5oCIyVReQJPSBwMSiJiZ6Ni1+rriHQWggO8x/Gm7vepKK2cXaDk72e26ZGszm1oKE7VVMe+WEP2SVV3DypP/VGyYFTEDSz5OMNqdQZJRuPtHM5bVoR1Do2/qJHb4BLP4O79zVIH1vy67FfScpN4vahtzdrLl9SVUtuaXX7GtaPvB4m/bN9c20nIyO9EELHBLuJpNob+HHX++06rnzLZ9jJGk7EXIZT6BCttqG2eVc6S1wd7FgwOoKfd2dx55dJDA334q2rhrdePGZJygotUO7kyd58zfDY8ooAYGzIWOxx50CtFjjvi8FiY2URJTo9DjpndKLnf832/BmeTlz8rKaPWiKE4K7hd5FXmcdn+z9rtv+ykeGEeDrx3K/NVwVLd2ayJCmTO6bGcOUYLSjZmZTT0qpavt+upTPuaG+Q2rQimPHWHj5Yd5SaOovAt05nUoFsTHV9NS9se4EBXgOY139es/1H2tGV7HTi6WzPwAA3MorHEF9dzRuHv6Wmvo0qYCmp3PgeScb+zJ95rlaQJo2aGmgbXDM2Ejudjn5+Lry/cCTO9nZtHgNodRlZOzXJbmBf/j68Hb2budlsDYPOwGCPKdQ77afA0bOPxgi0OgKXXhAoBps3BL6aOFRrRVZAon8ik8Mm8/6e9ykyqQqasbfTcef0GHalF/PrvpPumsyiSh76fjdDwz25dUp/Qjyd8HQ2tNmAvDWW7MigvKaeMf282Z9ZQnVd224mWZ6HEUG+0ZXHftzHuS/8yc+7s1qNMby24zUyyjK4d8S96K1IQhxpZ5/i08noKG9WZNhzR2kNWbWlVo20JeWH1+NbeZTdgecT7e+mFaRBu9xDgR6OLLtzAl/ffHbHVD7NaaMmQ7A3fy+DfAbZbKDYkrnRcxGinh9d3fuea8hoRF9TSrlO4N4LBOdAGQLtsY1VAcAdQ++gvLac9/c0d0NcMDSEfr4uPP/rIYxGidEouWfxTuqMkhcuScROr0MIQXywx0nlxQ4ipeTTjccZHOLB1WdHUlNv5EBW226m4vxsCqUrD50Xzwd/HYm9nY6/fbadi97cwLZjzX3r6zLW8cHeD7hkwCUt5rofzi1DrxOEe1uXST4TjO7nQ2WtkXinfkyUDjy/7Xne3f1uiwYubcUblEonhs0yxTu8o8DOqd3pp9H+rrg5drAOImUFuPhDYAKVdZUcKTpi824hMzNihlFfFcRSR13HVwSZO04a2Z5ITRkCIxU6iddp6C98OrBxQ2CWmWjbEMR4xXBe//P4/MDnZJc37l1sp9fx93MGcPBEKT/uyuS9tUfZcCSfR86LJdIizz4uxJ2D2aWN3TPtZEtqIQdPlHLlmHASwzwBGjJZWqMkP5sC6c6ISG+mDPRn2R0TePqCwRwvqODCN9az6NuTrTnzKvN4YO0DRHtG84+R/2jxnEdyy4nwdm6/n/w0MCpKi3kcs+vH81k5zIqcyUvbX+LRDY82kxCvKi0g8sRytrhNJS4qWNuo04P/WV0iXGcVYz0cXqmtBnQ6DhYcVIFiC1wc7HCvG8Mhg5HDVa3H6Rqor4U//gXvTIUvF2ipuT2Rau1mr0YPHr1AeRQ6aQiEEN5CiBVCiGTTo9VaaiHEQtOYZCHEQtM2ZyHE/4QQB4QQe4UQT3dmLqeEOZOmpYBxyu/w+tgGSdlbEm+hXtbz5s43mw2dMziIswLdePrnA/xn+UHOjQ3gkhFhjcbEB3tQU28kOafjAeNPNh7DzdGOuUNCCPJwxM/NoV3FbLWlOZTq3Ik0NTmx0+u4bFQ4q+6dzMXDQ/lySxrZxVUYpZEH1z5IeW05z0581rqUtAlzn+LuxNfVgf5+LmyrCsKhupinE27jxoQb+S75O/72298aSYPsXPY2jtTgN+mmxifpIuE6q2Rs11JnozVJjn35Wkc1tSI4yRCvqegk/GBsh7s0LwXeOxf+fEZrdVpXqQX7eyKmXgR1dvW9ohcBdH5FsAj4XUoZA/xuet4IIYQ38AgwGhgFPGJhMJ6TUp4FDAXGCSFmdXI+HaOtFcGW97Q7RlNnqRDXEC4deCnfp3zPkeLGRUY6neDucwaQVVyFu5OBf1/QPMc8PkSTo93bQfdQbmk1v+zJ4uLhYTjZ6xFCMCTUk6T0ojaP1VcVIJ19m83FxcGOK0ZrAeyktEI+3vsx6zPX88+R/yTGK6bF89UbJal5Fd0aHzAzup8PK/K1/6EuZz+3D72dJ8c9ybYT27hq2VWkl6ZTW1eP94EvOGwXQ/yIiY1PEBCv3QSUNa8cPiXqajSBvxWPaJpOQgf9pwJafMDb0ZsA574pKncqDA0JI6Lcjf/ZG6lvSTxQStj6Prw1QVO3vfgjuPBdbV/WLuvHdDcNvQjqekUNAXTeEMwDPjL9/hEw38qYGcAKKWWBlLIQWAHMlFJWSCn/AJBS1gDbgTNbd99ajKCq5GRrwYM/N2y+YfANOOodeXXHq80OOSc2gLvPGcDbVw/Hx7V53nyEtzOuDnbs6WDAePHWNGrrJQvGnJRDGBruyZHccoorm3dSM5NXVo1rfTGOnv5W9w8KcsegF/x+ZBsvbX+J6eHTuXjAxVbHmkkvrKCm3tjtKwLQAsZJ1UHakxNaYdm86Hm8Nf0tcitzWbBsAR//+g4xMpW6xKuaB2kD4hode0qU5cKWd+GLy+HZKPhoDmx4DdyD4YJ3Guoz9uXvI84nTgWKLYgLdiesJIgcvZ5fDjfX9KIsB764TKt8Dx8Df9ugaWb5xGhFitk91RAUI4FaUWMzK4IAKaVZNyEbsHa7EwJYajanm7Y1IITwBM5DW1VYRQhxoxBiqxBia25uO32KbeHooWnEW3MNHVoO9dXgO1BT7TT5I32cfFgYt5AVx1awI2dH0zlyx7QYhrXQqUqnE8QGu3cohbTeKPls4zHGRfs0ugsfEuoJwK5WVgXbU/PxohQv3yCr+x0Nes4KMrCy4Hl8nX15dOyjbX5RmVNHe8SKIMqHMpwpcQzRVm9rX4TSE4wKGsWnsz/F2c6Z10+8TpK9KwOmX9P8BP5mQ9AJ99C318L/7tHOkXApXPYF3HcUrvkJBl8EQEVtBUeKj6j4QBPigj1wKQ8joraWResf5s6Vd55caR/fCG+O17q6zXoWFnwL7qb3sd5Ocw9l7ey2ubdGTXkhFUIgkbgZ+oghEEL8JoTYY+WnUYK51NI1OtzVXQhhB3wBvCylbFFTWEr5tpRyhJRyhJ9fG9rv7X9xq72LAdi3BNyCYMoDWiPqtI0NuxbGLSTENYT719xPaU3H/P3xwR7syyqh3oqipTVWHsghs7iKq8Y07lo1OFRzM7UWJ9h35Bh6IfELCLa6X0pJvfe3VJPHv8c/jYdD252UDptSR9tVTHaaCfRwJMLHmbe97gLPcK0PwvOD4Isr6Jd9iMv87sfLWMedwQFk11mROnbx0f7HnTEEeckw+BK4cyfMeR7Omg0OjT/8BwsPYpRGFR9ogreLPXpHPxZnZHN79CVsyt7EBT9cwBNLryDv47lg7wI3/AGjb9JqXiwJStBWBO2VWjmDlBbnN/Qi6DMrAinldCllvJWfH4ATQoggANOjNWdrBmAZNQ01bTPzNpAspXzxlK+iM7j4No8RVJdC8gqInadlfejtG7mHXAwuPDPxGbLLs3li4xPt1/0B4kPcqao1NuTit8UnG48R4O7A9EGNF1seTgb6+7mQlNby6uLIseMAGNysu4aWH1tOWu06avKm4caAds3ncG45Xi2JzXUDoyK9+fREBMa//gK3boGzb6Xu+Cb44lIu+v0i3sjOocZgxy2/32K1twT+safuGqqtgtIs8InWbipaoCFQ7KsMQVO8fANxlpIbgybwv/O+4xJDAN8V7GJ2WCBvjL2aCu9I6wcGJmhB2aLjZ3S+7aG8uKDBENhKjGApsND0+0LgBytjlgPnCiG8TEHic03bEEI8CXgAf+/kPE4dZyuGwOwWip0PDq4QNREO/K/R3ccQvyHckngLPx/9maXW/JstYA4YtydOkJpXzupDuVw+Khw7ffN/1ZAwT5LSiqwaouq6evJOmOyti4/V8y8+uJhg5zBq8qa2W05byxjqOW/u0f18KKqo5VBOKTmO4TxQfglxxS9wh7yXHJ9R9IuezYtTXia1JJW///H35hXIAXGQe1BLTewo5i8hr9Z7DO/N24uvky/+ztYNsi0TGKStVmsyduHz5ZU8cHAjS4LmMD58Oq/vfZ+FvyykrMbKTZO5Z0b27jM42/ZRXVZAvtBqTvrMiqANngbOEUIkA9NNzxFCjBBCvAsgpSwAngC2mH4el1IWCCFCgQeBWGC7ECJJCHF9J+fTcazpDe39XnMZhI3Wng+cpWUs5DVWq7wu/jpGBIzgqU1Pcayk7f62oOn3Oxp07Sos+2LTEfQ6weUtaOYnhnmSV1ZNZnFzvZy9mSW4mdPyLAXnTJwoP8HW7K3Mi56Du6N9uyUrjuSW078HBIrNjDbVEzy2dB+T/7OKxVvSuHxMfx75xz+JuuMn9Jd+zOjgMTw+9nG2ZG/h4fUPNzacAfFQXwP5hzv+4kWm/7lXZKvDzIFiRXMiwrT3tv3v/6cZ5Es/JWLG0zw/5XlemfoKyYXJ3LXqrmbqv/jHallZPTBgXFNeRI5OS9fuMzGC1pBS5kspp0kpY0wupALT9q1Syustxr0vpYw2/Xxg2pYupRRSykFSykTTz7udu5xToKkUdXWZli00aO5Jv+QAU1brwWWNDtXr9Px7wr8x6Azct/q+5m9WK9jpdQwKajtgXJP8B3/fMo0FMXUEuFvP6TcXllm7m9+WWoiPMMUvnJuvCJanLkcimdVvFkPCPNu1IigoryGvrJ1ic2eIUC8nQjyd2HAkn0kD/Fhx9yQenRvXLGvrvP7nccfQO/jfkf/xyo5XTu7oTOZQYar26NnyikAFilsnJiKMammg2DkCblgJg85r2Dc5bDKPjn2UjVkb+b/1/9e4QZS9M/gO6JEppLKymHy99v6zlRVB78fFB2rLT/ZNPfSL1gs3bv7JMR4h2lL0YPMGNYEugTw+9nH25u/llaRXmu23RnywB/syS6y2QDRzcNsqnKjmRrf1LY45K9Ade73OuiE4VkiUs2ml4NJ8RfBL6i8M8h5ElEcUiWGeHDxRSmVN69pFqw9pKyfzXXhPQAjB21cP54dbx/HGlcOJaqV38PWDr+fCmAt5Z/c7fLb/M0prSpE+MaCzO7WAcWGqlsbo2nJtwIGCA0ikWhG0QJC3Gzc5P8c9ni+B38Bm++dHz28w4C9tf6nxzsCEHrkioLqEYlNBpq3ECHo/TZvY71uiNXoPG9N43MDZkLbJavHZtIhpXDzgYj7Y8wEbMje0+ZLxIe6UVtdxvKDlpt1ZqZoqZsjxpdabzaMJ3sUGuzdz60gp2XqskAGu1WDv1qwXQFpJGrvzdjMzaiagrSzqjZLdbaxSVuw/ga+rQ0Pqak8hLtiDIabVUWsIIXhozENMCJnA05ufZuwXYxn+5dlMDwvh0oyf+Ntvf+PhdQ+z4tiKttVMQXMNeYY3z2ixwCw9rVYE1hFCkDD0bFYereBEiXVJ8OsHX8+lAy/l/T3vNxYXDBwMJRlQ3rPUSw21JZTaackUakXQW2ioLs7V3ELJKyB2bvMP94CZgNQCyVb4x8h/0M+jHw+sfYCCqtbVFOOCWw8Y780sxqk8HaPQI0oytFzqFkgM82R3ejF19SeXzWkFleSVVRPuWGE1UPxLqraymRWpubyGtOJiMlNTZ2T1wVymneWPrj0NWXoodjo7np/8PM9OfJZ7R9zLlbFXMsbeF5+aSgqrCvkj7Q/uXnU3U7+eypMbn2RX7q6Ws8IKU1t1C4EWH/B38sfPuYtSnvsg84aGYJTw485Mq/uFENw/6n6mhk3lmc3P8Gvqr9qOoATtMbtn1RM41pVRYTBgr7PHQd91DZlOJ8oQNOgN5UPycs0tFDu/+bigIVoD8iZxAjNOdk48O/FZSqpLeGLDE62+5IAANwx60WLA+PNNx4nQ5VAXPRMcPSHp8xbPlRjmSWVtPSkW6ajbjmuGyE9fajU+sOzoMob6DyXIVSvQ8XV1INTLqVURu81HCyitrmN6bO+XSHC0c2RW1CwWxi3k7uF382TEebyekcaX097gj0v+4M3pbzI2eCxLUpawYNkC5i6Zyzu73qGwqolaa+HxNgPFe/P3EuurVgOt0d/PlYRQD5YkZbQ4Rq/T88zEZxjiN4T719zP1uytmmsIelScoLquHmdZToXBrtesBkAZgpP+8/JcLVvINUArZ2+KEFr20OGVLXa1Gug9kFsSb+G347+xPLXJyqGuuiFF0d5Ox8BAN6u9Ccqq6/hxx3FCRD72gWdpvYUP/ASVRVZf03w3n3T85P6tqYW4OtjhUlfcLGMouTCZlKIUZkbObHae1gzBb/tP4GCnY3x083hDr6ehN8E+7HR2jAsZx7MTn+WPS/7gsbGP4e3ozcs7XmbeknksO7JMWyFUFmq9iFtJHS2vLSe1OFW5hdrB/MQQ9mSUkNKKIKOjnSOvTH2FYNdg7l51N8V6PXiE9ag4wYniatypoMpOrwxBr8LsGio6drKIzEozFkCLE9RWQOqaFk+3MG4hcT5x/GvTv066iEqz4Y2x8N0NDeO03gTFzdwOPyRl4F6bi556ze2QeIW2StnbvGcyQKSPMx5OBnZaSE1sO1bI0HBPREV+s0Dxz0d/Rid0nBt5bqPtQ8M8ySiqJLe0utlrSCn5bf8Jxkf74mTfwt+mN2POHMrZ12izm70bF8RcwEezPuLbud8S6hbKfWvu446Vd3Aia7s2qBXX0P78/SpQ3E7mDAlCJ2DJDuvuITOejp48N+k5imuKNb2vwIQetSLIKijCQdRSpe898QFQhkArY7dzgqQvWnYLmYmaAPauLbqHQPNBPz7ucUpqSnh689NacPnjeZCfojXUMBEX4kFhRW2jGgBz85nxPpqeD16REDxUy5luwT0khDDdzWuri9KqWg6eKGV4uKf22hauISklPx/9mdGBo/F1amwgWosTHDxRSnphZZ9wC1nFLQicvFpNIR3gNYBPZn3CvSPuZWPWRuavv49v3FyQrRgCFShuP/5ujoyP8WNJUkablfoDvQdyyYBLWHxoMQd9wrTPVk35GZpp6xTkaZl1VXqJay9pUwnKEJzUGyo+3rJbyIydA/SfoslNtPJmHeA1gBsTbuTnoz+z8rM5WlCx/1StErVOu+OOD9YaVljWE+xIK2J/VgnzI00ZK14R2vwSr4D0LVrBjRUSQz04dKKUipo6dhwvQkoYFWKvVUdbGIK9+XtJL0tnVlRzte/4YA/0OmHVPfSbqQXntLP6aGWsEJp7qI0UUr1Oz8K4hXw791sG2XvzmK8PN+x8gbSSNKvj9+XvI8A5oJnRVVhnfmIw6YWVVjvnNeW2obfhbu/Ov8r2IZGnr69EBykq1LIKK0Tv6UUAyhBomN0ng+a27BYyM3C2pi+TldTqsOsHXMZAaccT+hKKL3gbhlyuNUsvOKq9VJA7ep1gr4Uh+GzjcVzs9QxzLwGhB3eTKnfCpdrzFlYFQ0zpn3sySth2rBCdgATv+sbXhhYkNugMTIuY1uwcTvZ6Bga4NXIxmfltfw5DQj3wb6GwrU8QEAcn9oGx7e5x4e7hvOsUy8PFVewpPMD8H+bz8vaXqahtnA68L3+fWg10gBlxgTgZ9Hy/o+WgsRkPBw/uGHYH20tT+cXFuccokZYUaams5cZaZQh6HeY4gWURWUvEnKuVtluI0DWjpgLDV1fxRFYmhXYGni3YrAmTgbaMRZOAjvZzZU+mljlUVFHDT7symT80BPuS4+ARqsntArj6a6+780ur7fks3TrbjxcyMNAd17rG8hL1xnqWH13O+JDxuNtbb5+XGK4FjC0L3XJKq0hKK2ometfnCIjTCguLUts1XFd0nIsdgvlh3g/MiJzBO7vfYc73c1h6eClGaaSspozUklQVH+gALg52nBMbwP92Z7WrnesF0RcwyHsQz/l4U2GO2XQzFSVaXLC0vkoZgl6HV5SWfRBuvVl7I1x8NQ2ilgxBXTV8dSWkrmXQnNe4dvB1LD28lDU1JmFWkyEArYexuYjr2+0ZVNcZWTA6QgtcN01LHLoAyrLhyB/NXtKc/rn9eCE7jhcxPMLzZIGcaUWwPWc7OZU5Vt1CZhLDPCmtquNI3kl/68r92rz7bHzATIPURDtdDIWp4BVBgEsA/5rwLz6d/SmBLoE8uPZBrlx2JV8f+hpQ8YGOcv7QEIoqavnzUNs9R/Q6PQ+MfoAcvY538raegdm1TXVZAbVAlbFGxQh6HdMf0XTP23ILmRk4S0tZW/4g/PIA/O9e+PFOWHILfDAbDv8Oc1+BwRdx85Cb6e/Rn0e3/odSV/9GfVbjgz3ILa3mREkVn206xrBwT2KD3Ru+ZBoRM0Pz9+/41OqUhoR58vv+HMqq6xge4XWyAtrUIevnoz/jZOfEpNBJLV6WNe2i3/bnEOLpxFmBvefu5pTwGwSI9hkCoxGK0xoZ6yF+Q/h09qf8a/y/yC7P5vltzwPKEHSU8TG+eLvYt1pTYEmifyLnOYXykb6S40WnIBzYxdRVFPW6XgSgDIGGvQu4dqDyM3ae1t1s8zuw/WPY8422Qji6Wmtic95LMOwq7dR6e54Y9wR5lXk84euN0WJFYJakfnfNEY7klmurgZpyraah6YrAzl5rgHJwGVQ0r1weGuZJjam6eESEN1SYyu6dfak11rLi2Aomh03G2eDc4mX193PF1cGuIWBcWVPP2pRcpg/y7/stFu2dwbtf+wxBaZamWNokY0gndJzX/zx+Ov8nbkq4icsGXoaPk3UJcIV1DHod5yUE8du+E5RWtU8a/K7+F2MvJc+sf+w0z651quvq0VWXUNYLDYFdd0+gV+IVCYva3xBjsN9gbku8jZd3vIxLTQkPS4kQWttKgA/WpeLhZOAvCUFQYMoMspaWmHgFbHoD9nwLo25otMscJ/Bz09xEVORpDXUc3NiYsZai6qIGSYmW0OsEg0M8GgLG61LyqKo1Mq2vxwfMBMS1zxCYVUdbqCp2Njhz29Dbumxatsb8oSF8tOEYv+zJ5uIRYW2O9wsfx81/Psx/dTtYnb6aiaETz8Asm3OiuBp3UUGxKbbXmwyBWhGcIa4ffD3Xew3hGyc7/r3+UaSUuDrY0c/XhTqj5KLhoTga9BYa91HNTxKUoAltJX3WbJc5/XNEhJd2916erwWKheCX1F9ws3djXMi4NueZGO7J/qwSqmrr+f3ACVwd7Bjdr+eojZ5WAuKh4EjbOent7EOgODUSwzyJ8HFut3sIn2gWVNQRqXfhmc3PUF3fvCjyTJBVXIkbFRTbawq4KkagaIYQgjtiLmNhcQlfpHzHf7b+ByklcSb30BWjTc1nGu42WyhUSlygFaadaFwF62Sv51/nx3PrFFN2UsXJYrIt2Vs4O+hs7PVtt5ccEupJbb1kb2Yxv+3PYdIAPxzs+mA1sTUC4gAJOQdaH1d4DBBaZpeiyxFCMD8xhPWH81tUJG2ETo8hII77a505Xnqct3e9ffonaYWs4ircRQVlDpohUCsChVWE7wDuKSjiCt+RfLLvE17a/hI3jI/iifnx9Dc3eyk8plUvWxGLA7T4BGjxiCZcOjK8Ie5ART64+JBdnk1WeRZD/Ye2a45Dwz0B+GTDMXJLq5k2qI8WkVnDrGaZsa31cYWp4B7STN5b0XXMHxqClPDh+tR2pZISlMDY7BTm9p/L+7vf52CB9eLL00lWcRVuVFBu7wQoQ6BoCa9IhNCxyLEfFw+4mPf2vMfa/M+5aozF3b9Z2ril4KxbkBaobtI2sxnleeDsy85crdAm0T+xXVMMcHck0N2RH3ZmohMwZaANGQKPMO0L/njLzYAAU3pv6/LTis4R5evC+Ghf3lh1mOFPruCur5L4ZU92y82TAhOguph/Rl+Ku4M7D69/mDpj85qb00l2cSXe+krK7LXCS2UIFNaxswfPCERBCg+NeYj50fN5Y+cbvLPrnZNjrNUQWCKE1qKvLUNgEpxLyknCUe/IQO/m3Z9aIjHMEylhRKQ3Xi5tu5P6DEJAxFg4tqFVCZH29CFQdJ53F47g3atHMCMukD8O5nDzp9sY+sSv3PTJVtYfbtIgyrSa8yg4yoOjH2Rf/j4+2ffJGZ1vZnEVXrpKyuwMCAQuhp7T27stlCE40/jGQH4KOqHj0bMfZU6/Oby842WWpCzRvnys1RA0O0cbhqCuGqpLwNmHnbk7ifeNx6AztHuKiSb30HRbcguZCT9bK9wrPGp9f22Vlj6qAsWnHUeDnumxATx38RC2Pjidz68fzSUjwth+vIjrPtxKVa3F6sA/VpNhydrFORHnMDVsKq8lvcaxkmNnbL7ZphhBqd4OV4MrOtF7vl57z0z7Cj7RkH8YpESv0/P4uMcZEzSGx9Y/xsajv2oy1219yfgOgLITLfYoMNcZVDq6sz9/f7vdQmamneVPtL8rf0kI7tBxfYKIsdrjsRbcQ8UmgTnlGjqj2Ol1jI325fF58Txz4WAqa+sbi9MZnLTPRfYuhBA8OOZB7HX2PLr+0cZN708jWcWVuMhySnW6XtOr2IwyBGcan/7al32Jprtu0Bl4fvLzRHpEcveG/+Owwa5tt4PvAO3RojitESZ5ib1UUSfrSPRL7NAUYwLc+O3uSYR4OnXouD6B70BNkvpYC72n26ghUJx+Rkf5YNALVic3kaEIOtmbwN/Zn3tH3svWE1v55tA3p31O1XX1FJRV4WisoFT0rvgAKENw5mkiPgfam+b1aa/jgJ5bAvzJc/Zo/Rx+Jn9/C7LUZnmJpGqtujjBL6FTU7YpdDrNPdRSwNhsCFSMoNtwcbBjeIQXaw41iRMEJmhuvVJNNv386PMZHTia57c9T3Z59mmdU05JNa5o6rNlGHtVDQEoQ3Dm8YnRHpvczQe5BvGq/yQK9TpuS3qhmaRxIzwjtKrhluIEJnmJneVpRLpH4uXo1RUztx0ixmqFZaVWvjyKjoHeQetdoeg2JsT4sS+rhLwyi+KxsFHaY9pGQKtHeGTsI9Qb63li4xNtNrzpDJlFlbgL7TNbKutaVPjtqXTKEAghvIUQK4QQyaZHq984QoiFpjHJQoiFVvYvFUK03B6qL+EWBAZnLU7QhLiKMp4trWd/4UEWrVlEvbGFVDm9HXj3b9UQSCCpKLnD8QEFEN5KnMAczNepe6juZEKMpqq7LsViVRCUqHUbTF3XsCnMLYzbh97O6vTVzfuIdyEbjuTjgdkQ1NpcjGAR8LuUMgb43fS8EUIIb+ARYDQwCnjE0mAIIS4Ayjo5j96DTqd9iVuokDZQmMpk5zD+OfKf/JH2B89tfa7l8/jGtGwIyvM4ZmegqKakw/EBBZqv2eAMx63ECQqPKbdQDyAu2AMvZwOrLd1DdvbaquDYukZjFwxawCDvQfxny38or+36lpa19Ua+2Hyc8WFaqnVpfbXNxQjmAR+Zfv8ImG9lzAxghZSyQEpZCKwAZgIIIVyBu4EnOzmP3oVvtPVAr6lQacGgBVw56Eo+3f8p3yd/b/0cfgO1bmd1Nc33VeSR5K7pA6kVwSmgN0DoSOsB48I26jwUZwS9TjAu2pc1ybmNXT6R4zXhQAuFXr1Oz0NjHiKnMoc3kt7o8rn8vv8EJ0qqmR3jhATK6iptLkYQIKXMMv2eDVhznIYAlk1d003bAJ4A/gu04hDXEELcKITYKoTYmpvbdtOKHo1PtPaFYvklXl8LxekNXzL3jriX0UGjeWrTU+zP39/8HL4DQNZrvuymlOeR5OSMm70bUR5WxOsUbRMxTmtmb5miW1kI1cUqdbSHMCHGl5zSapJzLBwKEWMBCcc3Nhqb4JfAhTEX8un+T0kutLIa7wSfbDxGiKcTg30FFUJgRPa9GIEQ4jchxB4rP/Msx0nNLLc7GiOESAT6SylbuOVtjJTybSnlCCnlCD+/DvQO6In4RGtf4uYMFNCMgDQ2uB30Oj3PTHgGDwcP7lp1F8XVxY3PYU4hzbOSOVRRQJJBMMRvSK8qaulRRJwNSEjbfHJboak4SbmGegTjY7TvgdWW3cxCRmjB/CbuIYA7h92Jq70rT216qssCx4dzy1iXks8Vo8PRVZc0NKXpczECKeV0KWW8lZ8fgBNCiCAA02OOlVNkAJai4qGmbWcDI4QQqcBaYIAQYlXnLqeXYCWF1Fp+uo+TD89Pfp4TFSd4YO0DjQtjfE3ZR1biBMUVuRwWHa8fUFgQMgJ0hsZfKKqGoEcR4ulEfz8X1iRbxAkMjhA6wqoh8HL04s5hd7LtxDZ+OvJTl8zhs43HMegFl4wIg6riXtmdDDrvGloKmLOAFgI/WBmzHDhXCOFlChKfCyyXUr4hpQyWUkYC44FDUsrJnZxP78Cnv/ZoaQgaNO4b320O8RvCP0f+k9XpqxtrEtm7aCJpuc0Nwa5areJSxQc6gb0zBCc2Dhi38D9SdB8TYvzYdDS/sdxExFjI2glVJc3GXxhzIYN9B/Pfrf+ltKa0U69dUVPH19vSmBUfhJ+bA1SVnJSgNtiWIXgaOEcIkQxMNz1HCDFCCPEugJSyAC0WsMX087hpm+3i5KU1jWm6ItDZaeqXTbhs4GXMjprNa0mvsT7TIqXRWuaQ0UiSqEGPYLDv4NMzf1sh/GzI2A61ldrzwmPg6Kmpvyp6BBNifKmqNbLdUm4iYpzmZrV065nQCR0Pjn6QgqoCXk96vVOv/ePOTEqr6rjSrB5cVUxpL+xFAJ00BFLKfCnlNClljMmFVGDavlVKeb3FuPellNGmnw+snCdVShnfmbn0OnyaZA4VHtPu8HXNm8AIIXjk7Efo79mf+1bfR1aZKT7vOwDykrVm6maqitjpYM8AB99W+xMr2kHEODDWnuxPUJiq3EI9jDH9zHITFu6hsFHaTdWxtVaPifON45KBl/D5gc9PuW+BlJJPNh5jYIAbIyNN2fBVRZTaa5+5PhcjUJwmmqaQtvEl42xw5oXJL1BnrOPuVXdTU1+jGYLacijNbBhXV3qCXQ72JLq1fC5FOwkfDYiTaaSqD0GPw8XBjmHhXqyx1B2yd4HgoY0Ky5py+9Db8bD34KlNT52SKN3O9GL2ZJRw5dkRWmtYgOoSSg29rxcBKEPQffhEawqiZj9mO75kIj0ieXLck+zJ38O/N//bInPopHsoOXcnlTodid5nna6Z2w5OXpq88bF12qqr6LhaEfRAJsT4sjezidxExDjI3A411jPTPRw8uGv4XezI2cHSw0s7/JqfbDiGi72e84dauHKriikzaEVlyhAo2odl5lB1qaYP1I4vmWkR07h+8PV8c+gbvi415UNbBIyT8jT1xcSA4V09Y9sk4mxI36LJT9fXqNTRHsgEUxppI7mJiHFgrIP05nECM/Oi55Hol8jzW5+nqKqo3a9XWF7Dj7syOX9YCK4Odid3VJVQorfDXmePg753tTFVhqC7aDAEhzucn35b4m2MCx7Hv3a+QpKbd6MVQVJRMv51dQR1oCOZohUixkJNGRwwpRsq11CPIz7EA09nQ+M00vAxIHStuod0QsdDYx6ipKaEF7e/2O7X+3pbGjV1xpNBYjNVxZTp9b0uPgDKEHQf3v0Aoa0IOpifrtfpeWbiMwQ6B3K3jzu5efsa9iWVpzGkugbh4tvlU7ZJzAJ0SV9oj16qUrunYVVuwtFdk6VuqcGQiYHeA7ly0JV8m/wtSTlJbb6W0Sj5bNNxRkV6c1agRfWwlFrWkKDXVRWDMgTdh50DeIZrhqAhPz2y3Yd7OHjw4pQXKRNwT10atfW1nCg/QWZdOYm1UiusUXQe9yDt/3JiNyDAI7S7Z6SwwoRoX06UNJWbGKe59WqrWj32lsRbCHAO4ImNT7TZ8H5NSh7H8itYMCa88Y7aCpD1lEKv0xkCZQi6F59oTYW0MBUc3LXgZAcY6D2QxwMmscOg45kNj7MzdycAibre0zS7V2BeFbiHaAZc0eMYb5KlbuQeihwH9dVa0LgVnA3O3D/qfg4VHuKz/Z+1OvannZm4O9oxMz6w8Y4qTQKmlPpeFygGZQi6F98YU4wgVYsPmNPQOsDMqFn8taiErw4v4dWkV7FHMMhRuYW6lIiztUcVH+ixhHo508/PpXEaabjp/9ZKnMDM1PCpTAqdxGtJr7XYzUxKyfrD+Yzt74uDXZN6H5MhKOuFvQhAGYLuxSdaC0Smbzn1LxnfAdxZWMTZrpEcLT5KfL0Og3MvF+XraUSM0x5VxlCPZmKMHxuPWMhNOHuDf1yLhWWWCCG4f/T9SCl5ZvMzVsccy68go6iScdE+zXea0sBL62tUjEDRQcyaQ5WFp56f7hmBXm/Ps66xxHjFML2qFpytvFEVp453Pxj4Fxg4s7tnomiFc+MCqKo18tUWC9X7yHGa1ER9rfWDDv8BSZ/DvqWEZB/gpojZ/Hb8N1bvX9zsmHWHNbfT2GgrK27ziqC+qlfGCOzaHqI4bZhTSOHUDYHeDnyi8cw/xneXfwtPBYK1OxbFqSMEXP55d89C0QZn9/NhdJQ3r6xM4eIRoTjb22mruc1vQ2YShI08ObiuGn6+D7Y1VrxZCPwUEsi/1j3CyB3f4nTFVw371qfkE+juSD9fKzG4knRqgUpjjYoRKDqIeyjYmbJ7OuN2MIvP1ZRDXZUmaKdQ2BhCCP45cyB5ZdV8sC5V2xhh7j9t4R4qOg7vz9CMwLi/wx074OZ1cO2vGK78jgcH30KGwY63i3Y1HGI0SjYcyWdstM9JSQlL8pIblEdVjEDRMcz9i6Fz0gW+A6DwKJSaxOhUDYHCRhke4c20s/x588/DFFXUgKu/9vkw1xOk/AZvTdSSNC79DM55THP9BcZr2lLR0xg55k7musXwobOelGwt4+hAdikF5TWM69/CZyvvEKXekYCqI1CcCuY4gWd46+Naw3egSXZ3k/ZcxQgUNsy9MwZSVl3Hm3+a2rhGjNVaV656Gj69CNyC4MZVMGhOy+cYsABXo5HHNz6BURpZb4oPjLMWHwDNEJg+w70xRqAMQXcTOw/iL+xcAZi5W5m5iYpyDSlsmEFB7swdEsyH64+SU1IFEeOhugRW/RsSLoHrfzt5A9YCXkGJ3FtQxI7iFL5N/pZ1KXn083Mh0MPK57S2EorSKHXXagtUjEDRcQZfBBe937lzmA2BWS7ZRa0IFLbN3ecMoK5e8vLKZOg/FUJHwuzn4Py3NJnqtvCKZG5lLaPsfXlh2wtsPp7K2P4tfK7yDwOSMldtvzIEiu7B3Lay4LD2XK0IFDZOhI8Ll44M48vNaRyrctRWAaNuaH/Rpk6P8Inm/4weVNZWUe+1tNX4AECpkyegDIGiOzH3JtAZwKH3vREViq7mjmkx2OkFL6xo3te7XfgOIDL/GAmuF2Lw2InOpYVuZnnJgOi13clAGYK+g9kQuPieklSFQtHXCHB3ZOHYSH7YmcmB7OaN7NvEdwAUplKTMxq7+gBe2PE0lXWVzcflHQLPMEqNVQiEChYruhE/kyFQbiGFooG/TeqPq4Mdzy0/hd7Eflo2XnHaYSZ7/42Msgze3Plm83F5h8B3AGU1ZbgYXNCJ3ve12vtmrLBOw4pABYoVCjOezvbcNLEfv+3P4bvt6R072JSEESnTmR87kQtiLuDjvR9zqNDC1WQ0alLyvgMoqSnplfEBUIag7+Br6kimaggUikZcOz6KERFe3L14J/d/t+ukKF1b+GiGYIA+i5GRXtw9/G7cHdx5bMNj1BtN5yjN1HoR+ERTVlPWK+MDoAxB38HFVytKM715FQqFhrO9HV/cOIabJ/Xni81pzH9tHSmWDWxawt6ZEzp/Rrjk4mxvh4eDB/8Y+Q925e7im0PfaGPMbWJ9B1BaW4qbQa0IFN2JEHDzWphwT3fPRKHocRj0OhbNOosP/jqSnNJq5r66tk1XUVFFDfvrghigz2rY9peovzAmaAwvbX+J3IpcU8YQDTECm3QNCSG8hRArhBDJpkerLbaEEAtNY5KFEAstttsLId4WQhwSQhwQQlzYmfnYPI4eYGff3bNQKHosUwb6s+yOCcQHe3D34p384+udVNRYb0+58Ug+h43B+FQd02IBaMJ2D415iOr6ap7d8qy2InDwAFd/m44RLAJ+l1LGAL+bnjdCCOENPAKMBkYBj1gYjAeBHCnlACAW+LOT81EoFIpWCfRw5PMbRnPblGi+2Z7O3FfXsS+zeXrpupR8jutC0ddXQcnJ1UOEewQ3JNzAL6m/sDYvSQsqC0FZbVmvTB2FzhuCecBHpt8/AuZbGTMDWCGlLJBSFgIrAHOHj2uBfwNIKY1SyjwrxysUCkWXYqfXce+MgXxy7WiKK2uZ/9o6Plh3FCllw5h1h/NwCDpLe5LXuCjt2vhrifKI4sn6E1T69EdKabuuISBASml2oGUDAVbGhAAWLYNIB0KEEJ6m508IIbYLIb4WQlg7HgAhxI1CiK1CiK25ubktDVMoFIp2Mz7Gl1/unMD4GF8e+3Ef1320lfyyarKLqziSW05YTKI2MLexIbDX2/N/w+8lQy94S19GZV0l9bJ3Nq6HdhgCIcRvQog9Vn7mWY6TmimVLZzGGnZAKLBeSjkM2AA819JgKeXbUsoRUsoRfn6qJ69CoegafFwdeG/hCB49L5a1KXnMemmNJlYHDBsUDU5ezVYEACN1rswvLeOj4r1sz9H6FvRWQ9Bmq0op5fSW9gkhTgghgqSUWUKIICDHyrAMYLLF81BgFZAPVADfmbZ/DVzXvmkrFApF1yGE4JpxUYzu58PtX+zg803H8XI2MCjIQ6vRsWIIyEvmnoIi/vQJ5rENjwG9U2cIOu8aWorW5hPT4w9WxiwHzhVCeJmCxOcCy00riB85aSSmAfs6OR+FQqE4ZQYFufPjbeO5cWI/7pgWg04nTraCbUreITyl4J7hd5Ndng2Au6H3dSeDzhuCp4FzhBDJwHTTc4QQI4QQ7wJIKQuAJ4Atpp/HTdsA7gMeFULsAq4CVBK8QqHoVpzs9TwwexB/HRelbfAbCOW5UFHQeGDeIfCOYm7MBYwMHAn03hVBm66h1pBS5qPdyTfdvhW43uL5+0Cz7itSymPAxM7MQaFQKE4rZh2vvGStr7EZk8aQEILHxj7G27veJsard1b2q8pihUKhaI0GQ2ChYGqsNxkC7Ys/zC2MJ8Y9gZOdUzdMsPMoQ6BQKBSt4RkOeofGcYKiY1Bf02e0vZQhUCgUitbQ6bU7f8taAguNob6AMgQKhULRFk0zhxpUR9WKQKFQKGwD34GaO6i2Snued0jrBujs3b3z6iKUIVAoFIq28I0BaYSCw9rzvOQ+4xYCZQgUCoWibfxMHQBzTZlDecl9xi0EyhAoFApF2/hEA0IzABUFUJGnVgQKhUJhUxictDTSvIMWGUNqRaBQKBS2he8ALUjcxzKGQBkChUKhaB9+AyEvBXIPgN4ePCO6e0ZdhjIECoVC0R58Y6CuEg7/ocUMdPrunlGXoQyBQqFQtAdfU+ZQzt4+5RYCZQgUCoWifVhmCfWhjCFQhkChUCjah4sPOPtovytDoFAoFDaK2QD4RHfvPLoYZQgUCoWivZgNQR+LEXSqQ5lCoVDYFCOuBZ/+4ODW3TPpUpQhUCgUivYSnKj99DGUa0ihUChsHGUIFAqFwsZRhkChUChsHGUIFAqFwsZRhkChUChsnE4ZAiGEtxBihRAi2fTo1cK4haYxyUKIhRbbLxdC7BZC7BJC/CKE8O3MfBQKhULRcTq7IlgE/C6ljAF+Nz1vhBDCG3gEGA2MAh4RQngJIeyAl4ApUsoEYBdwWyfno1AoFIoO0llDMA/4yPT7R8B8K2NmACuklAVSykJgBTATEKYfFyGEANyBzE7OR6FQKBQdpLMFZQFSyizT79lAgJUxIUCaxfN0IERKWSuE+BuwGygHkoFbW3ohIcSNwI2mp2VCiIOnOGdfIO8Uj+3NqOu2LdR12xbtvW6r3XTaNARCiN+AQCu7HrR8IqWUQgjZjomYz2sA/gYMBY4ArwD3A09aGy+lfBt4u73nb+V1t0opR3T2PL0Ndd22hbpu26Kz192mIZBSTm/lxU8IIYKklFlCiCAgx8qwDGCyxfNQYBWQaDr/YdO5FmMlxqBQKBSK00tnYwRLAXMW0ELgBytjlgPnmgLEXsC5pm0ZQKwQws807hxgfyfno1AoFIoO0tkYwdPAYiHEdcAx4BIAIcQI4GYp5fVSygIhxBPAFtMxj0spC0zjHgNWCyFqTcdf08n5tIdOu5d6Keq6bQt13bZFp65bSNlut75CoVAo+iCqslihUChsHGUIFAqFwsaxGUMghJgphDgohEgRQvTp7CQhxPtCiBwhxB6Lbe2SA+nNCCHChBB/CCH2CSH2CiHuNG3v09cuhHAUQmwWQuw0Xfdjpu1RQohNpvf8V0II++6e6+lACKEXQuwQQvxket7nr1sIkWqS50kSQmw1bTvl97lNGAIhhB54DZgFxAKXCyFiu3dWp5UP0aq3LWlTDqQPUAfcI6WMBcYAt5r+z3392quBqVLKIWhp2TOFEGOAZ4AXpJTRQCFwXfdN8bRyJ40zDm3luqdIKRMt6gdO+X1uE4YATeMoRUp5REpZA3yJJo/RJ5FSrgYKmmxujxxIr0ZKmSWl3G76vRTtyyGEPn7tUqPM9NRg+pHAVOAb0/Y+d90AQohQ4C/Au6bnAhu47hY45fe5rRgCqzIX3TSX7qI9ciB9BiFEJFrV+iZs4NpN7pEktKLOFcBhoEhKWWca0lff8y8C/wSMpuc+2MZ1S+BXIcQ2k/wOdOJ9rprX2yAdlQPpbQghXIFvgb9LKUu0m0SNvnrtUsp6IFEI4Ql8D5zVvTM6/Qgh5gA5UsptQojJ3TydM814KWWGEMIfWCGEOGC5s6Pvc1tZEWQAYRbPQ03bbIkTJhkQWpED6fWYNKy+BT6TUn5n2mwT1w4gpSwC/gDOBjxNcu/QN9/z44C5QohUNHfvVDRp+75+3UgpM0yPOWiGfxSdeJ/biiHYAsSYsgnsgcvQ5DFsifbIgfRqTP7h94D9UsrnLXb16WsXQviZVgIIIZw4KdfyB3CRaVifu24p5f1SylApZSTaZ3qllHIBffy6hRAuQgg38+9osj176MT73GYqi4UQs9H8iXrgfSnlU907o9OHEOILNKE/X+AEWmOgJcBiIByTHIhZ6qOvIIQYD6xBkzY3+4wfQIsT9NlrF0IkoAUH9Wg3d4ullI8LIfqh3Sl7AzuAK6WU1d0309OHyTV0r5RyTl+/btP1fW96agd8LqV8Sgjhwym+z23GECgUCoXCOrbiGlIoFApFCyhDoFAoFDaOMgQKhUJh4yhDoFAoFDaOMgQKhULRQxFCXGwSEjSaGn6155hwIcSvQoj9JgHGyLaOUYZA0aMRQtSbFBb3CCG+FkI494A5TRZCjO3kOYKFEN+0PbLRMdcIIV41/X6zEOLqzsxB0bMwva8+bLJ5D3ABsLoDp/oY+I+UchBaoVmbhWXKECh6OpUmhcV4oAa4uT0HWVSWng4mAx0yBE3nI6XMlFJe1NL4tpBSviml/PhUj1f0DqSU+6WUB5tuN2lL/UcIsUUIsUsIcZNpeyxgJ6VcYTq+TEpZ0dbrKEOg6E2sAaKFEOeZ9OZ3CCF+E0IEAAghHhVCfCKEWAd8IoSIFEKsEUJsN/2MNY2bLIT4UwjxgxDiiBDiaSHEAqFp+u8WQvQ3jfMTQnxr+rBtEUKMMy2zbwbuMq1UJlgbZ20+lhdimtse0+/XCCG+E0L8IjQt+Wctxv1VCHFICLEZTVIBi3Pfa/o92vR32Gm6TvP8/2HxRWHuUeAihPifaeweIcSlp+U/pTjdXAcUSylHAiOBG4QQUcAAoMj0ftphMhb6tk6mROcUvQLTHfUs4BdgLTDGJKx1PZr65D2mobFoglyVJjfSOVLKKiFEDPAFYPazDgEGocl1HwHelVKOElozm9uBv6Pp1rwgpVwrhAgHlkspBwkh3gTKpJTPmeb2edNxpnM3mk8bl5iIppZaDRwUQryC1l/hMWA4UIwmnbDDyrGfAU9LKb8XQjgCOiHEuUAMmmtAAEuFEBMBPyBTSvkX09w92piX4jQjhNgEOACugLfQVGQB7pNSLm/hsHOBBCGEeVXpgfb/tgMmoL2XjgNfAdegSa+0iDIEip6Ok8UHYw3aG3og8JXQhLXsgaMW45dafOkagFeFEIlAPdrdkpktZsleIcRh4FfT9t3AFNPv04FYcVK91F1oyqZNaW3c0nYYAdAaihSb5rMPiECTCFklpcw1bf+qyTUgNM2ZECnl9wBSyirT9nPRvizMhsMV7YtiDfBfIcQzwE9SyjXtmJviNCKlHA0NMhnXSCmvacdhAri9qaEQWkOiJCnlEdPzJWhNmpQhUPRqKqWUiZYbTHfLz0spl5o+PI9a7C63+P0uNK2lIWhu0CqLfZbaM0aL50ZOfi50aCsPy+Ow+MKnHePKmw5uAcv51NP5z6YA/i2lfKvZDiGGAbOBJ4UQv0spH+/kaynOPMuBvwkhVkopa4UQA9BUVregqa/6mW4gpgJb2zqZihEoeiMenJQWXtjGuCwppRG4Ck2UrSP8iuYmAsC0sgAoBdzaMa6zbAImCSF8hCavfXHTAaZObOlCiPmm13YwucSWA9eaVyZCiBAhhL8QIhiokFJ+CvwHGNZFc1WcBoQQ5wsh0tFkxf8nhDCvAN4F9gHbTbGmt9CCxPXAvcDvQojdaDcE77T1OmpFoOiNPAp8LYQoBFYCUS2Mex34Vmhplr/Q/rtzM3cArwkhdqF9VlajBYp/BL4RQsxDMwAtjesUUsosIcSjwAagCEhqYehVwFtCiMeBWuBiKeWvQohBwAbTyqQMuBKIBv4jhDCaxv6ts/NUdA1SylXAqibbvuek0qjldiOasu4DVvatABI68tpKfVShUChsHOUaUigUChtHGQKFQqGwcZQhUCgUChtHGQKFQqGwcZQhUCgUChtHGQKFQqGwcZQhUCgUChvn/wHqt6bqXWGpygAAAABJRU5ErkJggg==\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(np.arange(1000000,1000050,1), reverse_top10fft[1000000:1000050], label = \"FFT top-10%\")\n", + "plt.plot(np.arange(1000000,1000050,1), concr[1000000:1000050], label = \"Original Parameters\")\n", + "plt.plot(np.arange(1000000,1000050,1), reverse_top10wv[1000000:1000050], label = \"Sym2 top-10%\")\n", + "\n", + "plt.title('Parameter Values') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.legend()\n", + "plt.draw()\n", + "plt.savefig(\"ParametersWaveletHaar.png\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## FFT Training<a class=\"anchor\" id=\"ffttrain\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": { + "id": "e65Izyv0s-yE" + }, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "eqOXilqMs-yF", + "outputId": "06799a3b-983b-4f51-a7bd-a901c041bd05" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.136391 [ 0/735856]\n", + "loss: 1.387546 [64000/735856]\n", + "loss: 1.009362 [128000/735856]\n", + "loss: 0.568759 [192000/735856]\n", + "loss: 0.796950 [256000/735856]\n", + "loss: 0.670068 [320000/735856]\n", + "loss: 0.625332 [384000/735856]\n", + "loss: 0.557147 [448000/735856]\n", + "loss: 0.701893 [512000/735856]\n", + "loss: 0.670033 [576000/735856]\n", + "loss: 0.575888 [640000/735856]\n", + "loss: 0.654841 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 82.0%, Avg loss: 0.578153 \n", + "\n", + "loss: 0.776733 [ 0/735856]\n", + "loss: 0.519993 [64000/735856]\n", + "loss: 0.599282 [128000/735856]\n", + "loss: 0.885723 [192000/735856]\n", + "loss: 0.514714 [256000/735856]\n", + "loss: 0.539040 [320000/735856]\n", + "loss: 0.422559 [384000/735856]\n", + "loss: 0.382564 [448000/735856]\n", + "loss: 0.412677 [512000/735856]\n", + "loss: 0.360731 [576000/735856]\n", + "loss: 0.534333 [640000/735856]\n", + "loss: 0.379236 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.1%, Avg loss: 0.463718 \n", + "\n", + "loss: 0.367664 [ 0/735856]\n", + "loss: 0.339760 [64000/735856]\n", + "loss: 0.653718 [128000/735856]\n", + "loss: 0.410070 [192000/735856]\n", + "loss: 0.554535 [256000/735856]\n", + "loss: 0.578007 [320000/735856]\n", + "loss: 0.421670 [384000/735856]\n", + "loss: 0.599983 [448000/735856]\n", + "loss: 0.262858 [512000/735856]\n", + "loss: 0.333737 [576000/735856]\n", + "loss: 0.361296 [640000/735856]\n", + "loss: 0.468058 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.9%, Avg loss: 0.420345 \n", + "\n", + "loss: 0.443198 [ 0/735856]\n", + "loss: 0.507409 [64000/735856]\n", + "loss: 0.554008 [128000/735856]\n", + "loss: 0.304086 [192000/735856]\n", + "loss: 0.482780 [256000/735856]\n", + "loss: 0.349616 [320000/735856]\n", + "loss: 0.402055 [384000/735856]\n", + "loss: 0.345523 [448000/735856]\n", + "loss: 0.364194 [512000/735856]\n", + "loss: 0.310542 [576000/735856]\n", + "loss: 0.441185 [640000/735856]\n", + "loss: 0.276955 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.8%, Avg loss: 0.390410 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " topk = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat))\n", + " top10[topk.indices] = flat[topk.indices]\n", + " g.grad = top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# it converges slower than without gradient compression" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "import torch.fft as fft" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.122382 [ 0/735856]\n", + "loss: 1.659356 [64000/735856]\n", + "loss: 1.175072 [128000/735856]\n", + "loss: 1.030752 [192000/735856]\n", + "loss: 0.891644 [256000/735856]\n", + "loss: 0.732518 [320000/735856]\n", + "loss: 0.613185 [384000/735856]\n", + "loss: 0.483264 [448000/735856]\n", + "loss: 0.580724 [512000/735856]\n", + "loss: 0.509457 [576000/735856]\n", + "loss: 0.661517 [640000/735856]\n", + "loss: 0.621521 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 81.7%, Avg loss: 0.570322 \n", + "\n", + "loss: 0.543810 [ 0/735856]\n", + "loss: 0.339085 [64000/735856]\n", + "loss: 0.495473 [128000/735856]\n", + "loss: 0.384833 [192000/735856]\n", + "loss: 0.418521 [256000/735856]\n", + "loss: 0.614597 [320000/735856]\n", + "loss: 0.515266 [384000/735856]\n", + "loss: 0.738823 [448000/735856]\n", + "loss: 0.423178 [512000/735856]\n", + "loss: 0.473593 [576000/735856]\n", + "loss: 0.518021 [640000/735856]\n", + "loss: 0.497685 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 84.0%, Avg loss: 0.474809 \n", + "\n", + "loss: 0.575689 [ 0/735856]\n", + "loss: 0.456497 [64000/735856]\n", + "loss: 0.429356 [128000/735856]\n", + "loss: 0.563055 [192000/735856]\n", + "loss: 0.486054 [256000/735856]\n", + "loss: 0.542747 [320000/735856]\n", + "loss: 0.441926 [384000/735856]\n", + "loss: 0.461542 [448000/735856]\n", + "loss: 0.502812 [512000/735856]\n", + "loss: 0.383888 [576000/735856]\n", + "loss: 0.266721 [640000/735856]\n", + "loss: 0.490470 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.8%, Avg loss: 0.423047 \n", + "\n", + "loss: 0.302303 [ 0/735856]\n", + "loss: 0.421864 [64000/735856]\n", + "loss: 0.376742 [128000/735856]\n", + "loss: 0.259237 [192000/735856]\n", + "loss: 0.368860 [256000/735856]\n", + "loss: 0.400204 [320000/735856]\n", + "loss: 0.310619 [384000/735856]\n", + "loss: 0.320007 [448000/735856]\n", + "loss: 0.305337 [512000/735856]\n", + "loss: 0.375540 [576000/735856]\n", + "loss: 0.362421 [640000/735856]\n", + "loss: 0.347816 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.3%, Avg loss: 0.400034 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " \n", + " flat_fft = fft.rfft(flat)\n", + " topk = torch.topk(flat_fft.abs(), round(0.1*len(flat_fft)), dim=0, sorted=False)\n", + " top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + " top10[topk.indices] = flat_fft[topk.indices]\n", + " reverse_top10 = fft.irfft(top10)\n", + " g.grad = reverse_top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.125680 [ 0/735856]\n", + "loss: 1.490153 [64000/735856]\n", + "loss: 0.797238 [128000/735856]\n", + "loss: 0.703639 [192000/735856]\n", + "loss: 0.862654 [256000/735856]\n", + "loss: 0.674491 [320000/735856]\n", + "loss: 0.633835 [384000/735856]\n", + "loss: 0.537149 [448000/735856]\n", + "loss: 0.579062 [512000/735856]\n", + "loss: 0.468447 [576000/735856]\n", + "loss: 0.488582 [640000/735856]\n", + "loss: 0.529873 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 83.8%, Avg loss: 0.489548 \n", + "\n", + "loss: 0.573154 [ 0/735856]\n", + "loss: 0.466781 [64000/735856]\n", + "loss: 0.468422 [128000/735856]\n", + "loss: 0.449423 [192000/735856]\n", + "loss: 0.357713 [256000/735856]\n", + "loss: 0.391187 [320000/735856]\n", + "loss: 0.500866 [384000/735856]\n", + "loss: 0.368405 [448000/735856]\n", + "loss: 0.423239 [512000/735856]\n", + "loss: 0.533780 [576000/735856]\n", + "loss: 0.623185 [640000/735856]\n", + "loss: 0.380635 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.9%, Avg loss: 0.411804 \n", + "\n", + "loss: 0.485906 [ 0/735856]\n", + "loss: 0.522850 [64000/735856]\n", + "loss: 0.474864 [128000/735856]\n", + "loss: 0.453226 [192000/735856]\n", + "loss: 0.311791 [256000/735856]\n", + "loss: 0.370382 [320000/735856]\n", + "loss: 0.415271 [384000/735856]\n", + "loss: 0.448348 [448000/735856]\n", + "loss: 0.416761 [512000/735856]\n", + "loss: 0.392923 [576000/735856]\n", + "loss: 0.408733 [640000/735856]\n", + "loss: 0.369844 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.8%, Avg loss: 0.382454 \n", + "\n", + "loss: 0.351067 [ 0/735856]\n", + "loss: 0.441320 [64000/735856]\n", + "loss: 0.376012 [128000/735856]\n", + "loss: 0.326137 [192000/735856]\n", + "loss: 0.326353 [256000/735856]\n", + "loss: 0.337223 [320000/735856]\n", + "loss: 0.377199 [384000/735856]\n", + "loss: 0.453688 [448000/735856]\n", + "loss: 0.394669 [512000/735856]\n", + "loss: 0.462621 [576000/735856]\n", + "loss: 0.365274 [640000/735856]\n", + "loss: 0.414022 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.0%, Avg loss: 0.381759 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " \n", + " flat_fft = fft.rfft(flat)\n", + " topk = torch.topk(flat_fft.abs(), round(0.2*len(flat_fft)), dim=0, sorted=False)\n", + " top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + " top10[topk.indices] = flat_fft[topk.indices]\n", + " reverse_top10 = fft.irfft(top10)\n", + " g.grad = reverse_top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 229, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 230, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.128546 [ 0/735856]\n", + "loss: 1.380654 [64000/735856]\n", + "loss: 1.055664 [128000/735856]\n", + "loss: 0.687121 [192000/735856]\n", + "loss: 0.728443 [256000/735856]\n", + "loss: 0.731651 [320000/735856]\n", + "loss: 0.649674 [384000/735856]\n", + "loss: 0.474646 [448000/735856]\n", + "loss: 0.653415 [512000/735856]\n", + "loss: 0.450781 [576000/735856]\n", + "loss: 0.629819 [640000/735856]\n", + "loss: 0.548388 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 83.2%, Avg loss: 0.540368 \n", + "\n", + "loss: 0.767534 [ 0/735856]\n", + "loss: 0.474996 [64000/735856]\n", + "loss: 0.657538 [128000/735856]\n", + "loss: 0.388315 [192000/735856]\n", + "loss: 0.581206 [256000/735856]\n", + "loss: 0.421425 [320000/735856]\n", + "loss: 0.494563 [384000/735856]\n", + "loss: 0.541493 [448000/735856]\n", + "loss: 0.451657 [512000/735856]\n", + "loss: 0.382599 [576000/735856]\n", + "loss: 0.449485 [640000/735856]\n", + "loss: 0.408576 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.0%, Avg loss: 0.455863 \n", + "\n", + "loss: 0.487152 [ 0/735856]\n", + "loss: 0.566136 [64000/735856]\n", + "loss: 0.388435 [128000/735856]\n", + "loss: 0.435407 [192000/735856]\n", + "loss: 0.626423 [256000/735856]\n", + "loss: 0.436673 [320000/735856]\n", + "loss: 0.599878 [384000/735856]\n", + "loss: 0.567672 [448000/735856]\n", + "loss: 0.458641 [512000/735856]\n", + "loss: 0.479425 [576000/735856]\n", + "loss: 0.289777 [640000/735856]\n", + "loss: 0.392798 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.1%, Avg loss: 0.449504 \n", + "\n", + "loss: 0.616642 [ 0/735856]\n", + "loss: 0.266790 [64000/735856]\n", + "loss: 0.314584 [128000/735856]\n", + "loss: 0.314711 [192000/735856]\n", + "loss: 0.429452 [256000/735856]\n", + "loss: 0.363823 [320000/735856]\n", + "loss: 0.594678 [384000/735856]\n", + "loss: 0.417127 [448000/735856]\n", + "loss: 0.415177 [512000/735856]\n", + "loss: 0.406279 [576000/735856]\n", + "loss: 0.512797 [640000/735856]\n", + "loss: 0.259631 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.3%, Avg loss: 0.415515 \n", + "\n" + ] + } + ], + "source": [ + "# wavelet per layer\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'haar'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " \n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + " g.grad = reverse_top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.114821 [ 0/735856]\n", + "loss: 1.691283 [64000/735856]\n", + "loss: 0.739705 [128000/735856]\n", + "loss: 0.878835 [192000/735856]\n", + "loss: 0.893373 [256000/735856]\n", + "loss: 0.622142 [320000/735856]\n", + "loss: 0.729517 [384000/735856]\n", + "loss: 0.930510 [448000/735856]\n", + "loss: 0.564309 [512000/735856]\n", + "loss: 0.820855 [576000/735856]\n", + "loss: 0.592394 [640000/735856]\n", + "loss: 0.530982 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 82.1%, Avg loss: 0.576240 \n", + "\n", + "loss: 0.387244 [ 0/735856]\n", + "loss: 0.483110 [64000/735856]\n", + "loss: 0.544743 [128000/735856]\n", + "loss: 0.570393 [192000/735856]\n", + "loss: 0.511510 [256000/735856]\n", + "loss: 0.335736 [320000/735856]\n", + "loss: 0.671059 [384000/735856]\n", + "loss: 0.473634 [448000/735856]\n", + "loss: 0.559810 [512000/735856]\n", + "loss: 0.454633 [576000/735856]\n", + "loss: 0.571824 [640000/735856]\n", + "loss: 0.626598 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 84.3%, Avg loss: 0.482487 \n", + "\n", + "loss: 0.422876 [ 0/735856]\n", + "loss: 0.769186 [64000/735856]\n", + "loss: 0.351542 [128000/735856]\n", + "loss: 0.436626 [192000/735856]\n", + "loss: 0.628383 [256000/735856]\n", + "loss: 0.528591 [320000/735856]\n", + "loss: 0.573713 [384000/735856]\n", + "loss: 0.517758 [448000/735856]\n", + "loss: 0.434379 [512000/735856]\n", + "loss: 0.491439 [576000/735856]\n", + "loss: 0.494193 [640000/735856]\n", + "loss: 0.505279 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.1%, Avg loss: 0.454134 \n", + "\n", + "loss: 0.439892 [ 0/735856]\n", + "loss: 0.459202 [64000/735856]\n", + "loss: 0.245611 [128000/735856]\n", + "loss: 0.355409 [192000/735856]\n", + "loss: 0.490522 [256000/735856]\n", + "loss: 0.481495 [320000/735856]\n", + "loss: 0.426439 [384000/735856]\n", + "loss: 0.641797 [448000/735856]\n", + "loss: 0.423894 [512000/735856]\n", + "loss: 0.498421 [576000/735856]\n", + "loss: 0.344970 [640000/735856]\n", + "loss: 0.368346 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 84.2%, Avg loss: 0.466052 \n", + "\n" + ] + } + ], + "source": [ + "# per layer repeat\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'sym2'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " \n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " # print(len(coeff))\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + " g.grad = reverse_top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.135039 [ 0/735856]\n", + "loss: 1.154176 [64000/735856]\n", + "loss: 0.624926 [128000/735856]\n", + "loss: 0.605651 [192000/735856]\n", + "loss: 0.601686 [256000/735856]\n", + "loss: 0.532184 [320000/735856]\n", + "loss: 0.627395 [384000/735856]\n", + "loss: 0.411491 [448000/735856]\n", + "loss: 0.354714 [512000/735856]\n", + "loss: 0.393673 [576000/735856]\n", + "loss: 0.612208 [640000/735856]\n", + "loss: 0.619142 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.2%, Avg loss: 0.445382 \n", + "\n", + "loss: 0.429652 [ 0/735856]\n", + "loss: 0.396769 [64000/735856]\n", + "loss: 0.423508 [128000/735856]\n", + "loss: 0.576669 [192000/735856]\n", + "loss: 0.432909 [256000/735856]\n", + "loss: 0.515018 [320000/735856]\n", + "loss: 0.375972 [384000/735856]\n", + "loss: 0.376615 [448000/735856]\n", + "loss: 0.326449 [512000/735856]\n", + "loss: 0.360019 [576000/735856]\n", + "loss: 0.354862 [640000/735856]\n", + "loss: 0.522963 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.9%, Avg loss: 0.383029 \n", + "\n", + "loss: 0.319733 [ 0/735856]\n", + "loss: 0.486813 [64000/735856]\n", + "loss: 0.351780 [128000/735856]\n", + "loss: 0.327754 [192000/735856]\n", + "loss: 0.311207 [256000/735856]\n", + "loss: 0.421759 [320000/735856]\n", + "loss: 0.486802 [384000/735856]\n", + "loss: 0.327473 [448000/735856]\n", + "loss: 0.229189 [512000/735856]\n", + "loss: 0.395156 [576000/735856]\n", + "loss: 0.330383 [640000/735856]\n", + "loss: 0.240293 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.1%, Avg loss: 0.374847 \n", + "\n", + "loss: 0.364167 [ 0/735856]\n", + "loss: 0.325380 [64000/735856]\n", + "loss: 0.407133 [128000/735856]\n", + "loss: 0.229438 [192000/735856]\n", + "loss: 0.324557 [256000/735856]\n", + "loss: 0.312494 [320000/735856]\n", + "loss: 0.250331 [384000/735856]\n", + "loss: 0.405609 [448000/735856]\n", + "loss: 0.334161 [512000/735856]\n", + "loss: 0.305596 [576000/735856]\n", + "loss: 0.396855 [640000/735856]\n", + "loss: 0.267720 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.3%, Avg loss: 0.357564 \n", + "\n" + ] + } + ], + "source": [ + "# wavelet over entire flatten gradient\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'haar'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " flats = []\n", + " shapes = []\n", + " lens = []\n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " shapes.append(shape)\n", + " flat = g.grad.flatten()\n", + " flats.append(flat)\n", + " lens.append(len(flat))\n", + " flat = torch.cat(flats)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + "\n", + " \n", + " start_index = 0 \n", + " for i, key in enumerate(model.parameters()):\n", + " end_index = start_index + lens[i]\n", + " key.grad = reverse_top10[start_index:end_index].reshape(shapes[i])\n", + " start_index = end_index\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "import pywt" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.126535 [ 0/735856]\n", + "loss: 1.238513 [64000/735856]\n", + "loss: 0.947478 [128000/735856]\n", + "loss: 0.758107 [192000/735856]\n", + "loss: 0.538468 [256000/735856]\n", + "loss: 0.726651 [320000/735856]\n", + "loss: 0.523160 [384000/735856]\n", + "loss: 0.323133 [448000/735856]\n", + "loss: 0.439029 [512000/735856]\n", + "loss: 0.406259 [576000/735856]\n", + "loss: 0.490085 [640000/735856]\n", + "loss: 0.520512 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.0%, Avg loss: 0.449423 \n", + "\n", + "loss: 0.481995 [ 0/735856]\n", + "loss: 0.485922 [64000/735856]\n", + "loss: 0.363491 [128000/735856]\n", + "loss: 0.604679 [192000/735856]\n", + "loss: 0.318160 [256000/735856]\n", + "loss: 0.321950 [320000/735856]\n", + "loss: 0.355750 [384000/735856]\n", + "loss: 0.399116 [448000/735856]\n", + "loss: 0.283532 [512000/735856]\n", + "loss: 0.527641 [576000/735856]\n", + "loss: 0.413641 [640000/735856]\n", + "loss: 0.309524 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.0%, Avg loss: 0.406266 \n", + "\n", + "loss: 0.332639 [ 0/735856]\n", + "loss: 0.438504 [64000/735856]\n", + "loss: 0.375174 [128000/735856]\n", + "loss: 0.325330 [192000/735856]\n", + "loss: 0.311181 [256000/735856]\n", + "loss: 0.439757 [320000/735856]\n", + "loss: 0.357552 [384000/735856]\n", + "loss: 0.318609 [448000/735856]\n", + "loss: 0.265860 [512000/735856]\n", + "loss: 0.534769 [576000/735856]\n", + "loss: 0.287946 [640000/735856]\n", + "loss: 0.381077 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.0%, Avg loss: 0.377133 \n", + "\n", + "loss: 0.293545 [ 0/735856]\n", + "loss: 0.346547 [64000/735856]\n", + "loss: 0.489387 [128000/735856]\n", + "loss: 0.438751 [192000/735856]\n", + "loss: 0.376747 [256000/735856]\n", + "loss: 0.427431 [320000/735856]\n", + "loss: 0.381158 [384000/735856]\n", + "loss: 0.482535 [448000/735856]\n", + "loss: 0.229551 [512000/735856]\n", + "loss: 0.455859 [576000/735856]\n", + "loss: 0.332654 [640000/735856]\n", + "loss: 0.496725 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.5%, Avg loss: 0.358163 \n", + "\n" + ] + } + ], + "source": [ + "# rerun with alpha 0.2\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'sym2'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " flats = []\n", + " shapes = []\n", + " lens = []\n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " shapes.append(shape)\n", + " flat = g.grad.flatten()\n", + " flats.append(flat)\n", + " lens.append(len(flat))\n", + " flat = torch.cat(flats)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + "\n", + " \n", + " start_index = 0 \n", + " for i, key in enumerate(model.parameters()):\n", + " end_index = start_index + lens[i]\n", + " key.grad = reverse_top10[start_index:end_index].reshape(shapes[i])\n", + " start_index = end_index\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "v,i = torch.topk(torch.tensor([1,2,3,4]), 2 , dim=0, sorted=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([4, 3])" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([3, 2])" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "i" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.126898 [ 0/735856]\n", + "loss: 1.050626 [64000/735856]\n", + "loss: 0.652647 [128000/735856]\n", + "loss: 0.648297 [192000/735856]\n", + "loss: 0.636182 [256000/735856]\n", + "loss: 0.570731 [320000/735856]\n", + "loss: 0.509262 [384000/735856]\n", + "loss: 0.309913 [448000/735856]\n", + "loss: 0.538662 [512000/735856]\n", + "loss: 0.530801 [576000/735856]\n", + "loss: 0.507737 [640000/735856]\n", + "loss: 0.422813 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.5%, Avg loss: 0.435624 \n", + "\n", + "loss: 0.388328 [ 0/735856]\n", + "loss: 0.299637 [64000/735856]\n", + "loss: 0.420440 [128000/735856]\n", + "loss: 0.230143 [192000/735856]\n", + "loss: 0.374027 [256000/735856]\n", + "loss: 0.279048 [320000/735856]\n", + "loss: 0.495672 [384000/735856]\n", + "loss: 0.277394 [448000/735856]\n", + "loss: 0.395940 [512000/735856]\n", + "loss: 0.476103 [576000/735856]\n", + "loss: 0.550471 [640000/735856]\n", + "loss: 0.431940 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.7%, Avg loss: 0.391393 \n", + "\n", + "loss: 0.436391 [ 0/735856]\n", + "loss: 0.351771 [64000/735856]\n", + "loss: 0.352133 [128000/735856]\n", + "loss: 0.254270 [192000/735856]\n", + "loss: 0.357840 [256000/735856]\n", + "loss: 0.368416 [320000/735856]\n", + "loss: 0.401375 [384000/735856]\n", + "loss: 0.442322 [448000/735856]\n", + "loss: 0.538914 [512000/735856]\n", + "loss: 0.444955 [576000/735856]\n", + "loss: 0.322195 [640000/735856]\n", + "loss: 0.493332 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.9%, Avg loss: 0.374818 \n", + "\n", + "loss: 0.457855 [ 0/735856]\n", + "loss: 0.423867 [64000/735856]\n", + "loss: 0.274726 [128000/735856]\n", + "loss: 0.356364 [192000/735856]\n", + "loss: 0.341427 [256000/735856]\n", + "loss: 0.301665 [320000/735856]\n", + "loss: 0.409492 [384000/735856]\n", + "loss: 0.401218 [448000/735856]\n", + "loss: 0.616257 [512000/735856]\n", + "loss: 0.287706 [576000/735856]\n", + "loss: 0.321826 [640000/735856]\n", + "loss: 0.423405 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.6%, Avg loss: 0.357925 \n", + "\n" + ] + } + ], + "source": [ + "# rerun with alpha 0.2 and level 4\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'coif1'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " flats = []\n", + " shapes = []\n", + " lens = []\n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " shapes.append(shape)\n", + " flat = g.grad.flatten()\n", + " flats.append(flat)\n", + " lens.append(len(flat))\n", + " flat = torch.cat(flats)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " # print(len(coeff))\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.2*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + "\n", + " \n", + " start_index = 0 \n", + " for i, key in enumerate(model.parameters()):\n", + " end_index = start_index + lens[i]\n", + " key.grad = reverse_top10[start_index:end_index].reshape(shapes[i])\n", + " start_index = end_index\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.118358 [ 0/735856]\n", + "loss: 1.330925 [64000/735856]\n", + "loss: 0.899926 [128000/735856]\n", + "loss: 0.894990 [192000/735856]\n", + "loss: 0.475845 [256000/735856]\n", + "loss: 0.672299 [320000/735856]\n", + "loss: 0.728748 [384000/735856]\n", + "loss: 0.374176 [448000/735856]\n", + "loss: 0.621309 [512000/735856]\n", + "loss: 0.562943 [576000/735856]\n", + "loss: 0.567177 [640000/735856]\n", + "loss: 0.408742 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 84.7%, Avg loss: 0.461047 \n", + "\n", + "loss: 0.545014 [ 0/735856]\n", + "loss: 0.433877 [64000/735856]\n", + "loss: 0.513009 [128000/735856]\n", + "loss: 0.462199 [192000/735856]\n", + "loss: 0.371584 [256000/735856]\n", + "loss: 0.380919 [320000/735856]\n", + "loss: 0.448126 [384000/735856]\n", + "loss: 0.421078 [448000/735856]\n", + "loss: 0.531703 [512000/735856]\n", + "loss: 0.314307 [576000/735856]\n", + "loss: 0.345081 [640000/735856]\n", + "loss: 0.456303 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.6%, Avg loss: 0.392272 \n", + "\n", + "loss: 0.371980 [ 0/735856]\n", + "loss: 0.419902 [64000/735856]\n", + "loss: 0.344231 [128000/735856]\n", + "loss: 0.383977 [192000/735856]\n", + "loss: 0.586718 [256000/735856]\n", + "loss: 0.524982 [320000/735856]\n", + "loss: 0.333949 [384000/735856]\n", + "loss: 0.478536 [448000/735856]\n", + "loss: 0.346808 [512000/735856]\n", + "loss: 0.322247 [576000/735856]\n", + "loss: 0.281340 [640000/735856]\n", + "loss: 0.373933 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.8%, Avg loss: 0.379021 \n", + "\n", + "loss: 0.393135 [ 0/735856]\n", + "loss: 0.281718 [64000/735856]\n", + "loss: 0.488630 [128000/735856]\n", + "loss: 0.335369 [192000/735856]\n", + "loss: 0.342869 [256000/735856]\n", + "loss: 0.293455 [320000/735856]\n", + "loss: 0.391644 [384000/735856]\n", + "loss: 0.309957 [448000/735856]\n", + "loss: 0.277645 [512000/735856]\n", + "loss: 0.277113 [576000/735856]\n", + "loss: 0.242315 [640000/735856]\n", + "loss: 0.292711 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.3%, Avg loss: 0.366945 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " flats = []\n", + " shapes = []\n", + " lens = []\n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " shapes.append(shape)\n", + " flat = g.grad.flatten()\n", + " flats.append(flat)\n", + " lens.append(len(flat))\n", + " flat = torch.cat(flats)\n", + "\n", + " topk = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat))\n", + " top10[topk.indices] = flat[topk.indices]\n", + " \n", + " start_index = 0 \n", + " for i, key in enumerate(model.parameters()):\n", + " end_index = start_index + lens[i]\n", + " key.grad = top10[start_index:end_index].reshape(shapes[i])\n", + " start_index = end_index\n", + " \n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Node Training <a class=\"anchor\" id=\"nodetraining\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "9LpgzEw1s-xo" + }, + "outputs": [], + "source": [ + "# From Femnist.py\n", + "def read_file(file_path):\n", + " with open(file_path, \"r\") as inf:\n", + " client_data = json.load(inf)\n", + " print(\"loaded the data\")\n", + " return (\n", + " client_data[\"users\"],\n", + " client_data[\"num_samples\"],\n", + " client_data[\"user_data\"],\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QBu1kiw8s-xr" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "raw", + "metadata": { + "id": "jI3ixEN4s-xt", + "outputId": "ed969663-9e1e-4810-9507-52cdc426650a" + }, + "source": [ + "# From Femnist.py\n", + "for i in range(1):\n", + " cur_file = \"leaf/data/femnist/data/train/all_data_0_niid_0_keep_0_train_9.json\"\n", + " # test_file = \"leaf/data/femnist/data/test/all_data_0_niid_0_keep_0_test_9.json\"\n", + " # cur_file = test_file\n", + " clients, _, train_data = read_file(\n", + " os.path.join(train_dir, cur_file)\n", + " )\n", + " for cur_client in clients:\n", + " # self.clients.append(cur_client)\n", + " my_train_data[\"x\"].extend(train_data[cur_client][\"x\"])\n", + " my_train_data[\"y\"].extend(train_data[cur_client][\"y\"])\n", + " del train_data[cur_client]\n" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "wvHsSz8as-xw" + }, + "source": [ + "train_x = (\n", + " np.array(my_train_data[\"x\"], dtype=np.dtype(\"float32\"))\n", + " .reshape(-1, 28, 28, 1)\n", + " .transpose(0, 3, 1, 2)\n", + ")\n", + "train_y = np.array(my_train_data[\"y\"], dtype=np.dtype(\"int64\")).reshape(-1)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "K8X471SKs-xz", + "outputId": "cdf73c06-1323-4e76-850b-16324008d255" + }, + "source": [ + "len(train_y)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "EpWNELBrs-x0" + }, + "source": [ + "with open(train_dir+\"femnist.pkl\", \"wb\") as f:\n", + " pickle.dump({\"test_x\": train_x, \"test_y\": train_y}, f)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "mAEASHr2s-x1" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "7665.166666666667" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "735856 / 96\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "Am_XlcSSs-x3" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "evAd9ZvYs-x6" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "9_vIFakbs-x7", + "outputId": "3a8b546a-186f-4519-8c0b-e853986a8101" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856, 1, 28, 28)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_x\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "GPyZ2C8ws-x9" + }, + "outputs": [], + "source": [ + "NUM_CLASSES = 62\n", + "IMAGE_SIZE = (28, 28)\n", + "FLAT_SIZE = 28 * 28\n", + "PIXEL_RANGE = 256.0\n", + "import torch.nn.functional as F\n", + "\n", + "class CNN(nn.Module):\n", + " \"\"\"\n", + " Class for a CNN Model for FEMNIST\n", + "\n", + " \"\"\"\n", + "\n", + " def __init__(self):\n", + " \"\"\"\n", + " Constructor. Instantiates the CNN Model\n", + " with 28*28*1 Input and 62 output classes\n", + "\n", + " \"\"\"\n", + " super().__init__()\n", + " # 1.6 million params\n", + " self.conv1 = nn.Conv2d(1, 32, 5, padding=2)\n", + " self.pool = nn.MaxPool2d(2, 2)\n", + " self.conv2 = nn.Conv2d(32, 64, 5, padding=2)\n", + " self.fc1 = nn.Linear(7 * 7 * 64, 512)\n", + " self.fc2 = nn.Linear(512, NUM_CLASSES)\n", + "\n", + " def forward(self, x):\n", + " \"\"\"\n", + " Forward pass of the model\n", + "\n", + " Parameters\n", + " ----------\n", + " x : torch.tensor\n", + " The input torch tensor\n", + "\n", + " Returns\n", + " -------\n", + " torch.tensor\n", + " The output torch tensor\n", + "\n", + " \"\"\"\n", + " x = self.pool(F.relu(self.conv1(x)))\n", + " x = self.pool(F.relu(self.conv2(x)))\n", + " x = torch.flatten(x, 1)\n", + " x = F.relu(self.fc1(x))\n", + " x = self.fc2(x)\n", + " return x\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "bCgW8ClBs-x_" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856,)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_y\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "id": "oBGwcwZks-yA" + }, + "outputs": [], + "source": [ + "import os\n", + "from torch.utils.data import Dataset\n", + "\n", + "class FemnistDataset(Dataset):\n", + " def __init__(self, training, transform=None, target_transform=None):\n", + " if training:\n", + " with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)\n", + " self.data = train[\"train_x\"][10000:10000+7665,...]\n", + " self.label = train[\"train_y\"][10000:10000+7665,...]\n", + " else: \n", + " with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)\n", + " self.data = test[\"test_x\"]\n", + " self.label = test[\"test_y\"]\n", + " self.transform = transform\n", + " self.target_transform = target_transform\n", + "\n", + " def __len__(self):\n", + " return len(self.label)\n", + "\n", + " def __getitem__(self, idx):\n", + " return self.data[idx], self.label[idx]" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "U3boC_N4s-yC" + }, + "outputs": [], + "source": [ + "from torch.utils.data import DataLoader" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "sJsrQXkEs-yD" + }, + "outputs": [], + "source": [ + "trainset = FemnistDataset(True)\n", + "testset = FemnistDataset(False)\n", + "\n", + "train_dataloader = DataLoader(trainset, batch_size=16, shuffle=True)\n", + "test_dataloader = DataLoader(testset, batch_size=128, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "480" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(train_dataloader)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "id": "e65Izyv0s-yE" + }, + "outputs": [], + "source": [ + "lr = 0.001\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1487, -0.1003, 0.0990, -0.0245, -0.1023, 0.0974, -0.1139, -0.1425,\n", + " -0.1949, -0.0679, -0.0937, 0.0891, 0.0577, -0.1357, 0.0814, 0.1157,\n", + " -0.1997, -0.1665, -0.1546, 0.1150, 0.0895, -0.1049, -0.0980, -0.0980,\n", + " 0.0729, 0.1947, 0.0421, -0.0365, -0.1470, -0.1679, 0.0286, -0.0146])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "tensor([-0.0180, 0.0236, 0.1279, -0.1352, -0.1948, -0.0330, -0.1615, -0.0286,\n", + " -0.1762, 0.0040, 0.1570, -0.1069, -0.1074, -0.1417, -0.1171, 0.0359,\n", + " 0.1276, -0.1534, -0.1773, -0.1639, 0.1334, 0.0518, 0.0586, 0.1466,\n", + " 0.1283, 0.0443, -0.0982, -0.1739, -0.0061, 0.1047, -0.0291, 0.1525])" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "for p in model.parameters():\n", + " print(p.data.size())\n", + " p.data = torch.zeros(p.data.size())" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1487, -0.1003, 0.0990, -0.0245, -0.1023, 0.0974, -0.1139, -0.1425,\n", + " -0.1949, -0.0679, -0.0937, 0.0891, 0.0577, -0.1357, 0.0814, 0.1157,\n", + " -0.1997, -0.1665, -0.1546, 0.1150, 0.0895, -0.1049, -0.0980, -0.0980,\n", + " 0.0729, 0.1947, 0.0421, -0.0365, -0.1470, -0.1679, 0.0286, -0.0146])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "eqOXilqMs-yF", + "outputId": "06799a3b-983b-4f51-a7bd-a901c041bd05" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.158939 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 34.5%, Avg loss: 2.492351 \n", + "\n", + "loss: 2.274407 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 49.2%, Avg loss: 2.004063 \n", + "\n", + "loss: 2.080229 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 57.7%, Avg loss: 1.550052 \n", + "\n", + "loss: 1.220055 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 62.5%, Avg loss: 1.387109 \n", + "\n", + "loss: 0.547404 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 62.6%, Avg loss: 1.411219 \n", + "\n", + "loss: 0.666172 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 68.1%, Avg loss: 1.147880 \n", + "\n", + "loss: 0.539106 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 66.9%, Avg loss: 1.218418 \n", + "\n", + "loss: 1.057546 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 68.9%, Avg loss: 1.211012 \n", + "\n", + "loss: 0.315841 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 66.5%, Avg loss: 1.400047 \n", + "\n", + "loss: 0.659244 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 66.0%, Avg loss: 1.484381 \n", + "\n", + "loss: 0.437452 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 69.8%, Avg loss: 1.239514 \n", + "\n", + "loss: 0.675393 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 69.3%, Avg loss: 1.224045 \n", + "\n", + "loss: 0.409850 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 67.5%, Avg loss: 1.499410 \n", + "\n", + "loss: 0.942130 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 69.7%, Avg loss: 1.331600 \n", + "\n", + "loss: 0.193678 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 69.5%, Avg loss: 1.398448 \n", + "\n", + "loss: 0.120872 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 68.4%, Avg loss: 1.589930 \n", + "\n", + "loss: 0.099591 [ 0/ 7665]\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(20):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " #print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " #print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " #print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.001\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=0.001)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.158939 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 26.3%, Avg loss: 2.828093 \n", + "\n", + "loss: 2.478634 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 47.1%, Avg loss: 2.069258 \n", + "\n", + "loss: 2.099130 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 56.7%, Avg loss: 1.571264 \n", + "\n", + "loss: 1.343866 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 61.1%, Avg loss: 1.432287 \n", + "\n", + "loss: 0.783433 [ 0/ 7665]\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [18]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 48\u001b[0m X \u001b[38;5;241m=\u001b[39m X\u001b[38;5;241m.\u001b[39mto(device)\n\u001b[1;32m 49\u001b[0m y \u001b[38;5;241m=\u001b[39m y\u001b[38;5;241m.\u001b[39mto(device)\n\u001b[0;32m---> 50\u001b[0m pred \u001b[38;5;241m=\u001b[39m \u001b[43mmodel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mX\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 51\u001b[0m test_loss \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m loss_fn(pred, y)\u001b[38;5;241m.\u001b[39mitem()\n\u001b[1;32m 52\u001b[0m correct \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m (pred\u001b[38;5;241m.\u001b[39margmax(\u001b[38;5;241m1\u001b[39m) \u001b[38;5;241m==\u001b[39m y)\u001b[38;5;241m.\u001b[39mtype(torch\u001b[38;5;241m.\u001b[39mfloat)\u001b[38;5;241m.\u001b[39msum()\u001b[38;5;241m.\u001b[39mitem()\n", + "File \u001b[0;32m~/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/nn/modules/module.py:1102\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 1098\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m 1099\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m 1100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m 1101\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1102\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mforward_call\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1103\u001b[0m \u001b[38;5;66;03m# Do not call functions when jit is used\u001b[39;00m\n\u001b[1;32m 1104\u001b[0m full_backward_hooks, non_full_backward_hooks \u001b[38;5;241m=\u001b[39m [], []\n", + "Input \u001b[0;32mIn [11]\u001b[0m, in \u001b[0;36mCNN.forward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;124;03mForward pass of the model\u001b[39;00m\n\u001b[1;32m 30\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 40\u001b[0m \n\u001b[1;32m 41\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 42\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpool(F\u001b[38;5;241m.\u001b[39mrelu(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconv1(x)))\n\u001b[0;32m---> 43\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpool(F\u001b[38;5;241m.\u001b[39mrelu(\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconv2\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m))\n\u001b[1;32m 44\u001b[0m x \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mflatten(x, \u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m 45\u001b[0m x \u001b[38;5;241m=\u001b[39m F\u001b[38;5;241m.\u001b[39mrelu(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfc1(x))\n", + "File \u001b[0;32m~/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/nn/modules/module.py:1102\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 1098\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m 1099\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m 1100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m 1101\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1102\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mforward_call\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1103\u001b[0m \u001b[38;5;66;03m# Do not call functions when jit is used\u001b[39;00m\n\u001b[1;32m 1104\u001b[0m full_backward_hooks, non_full_backward_hooks \u001b[38;5;241m=\u001b[39m [], []\n", + "File \u001b[0;32m~/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/nn/modules/conv.py:446\u001b[0m, in \u001b[0;36mConv2d.forward\u001b[0;34m(self, input)\u001b[0m\n\u001b[1;32m 445\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mforward\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;28minput\u001b[39m: Tensor) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Tensor:\n\u001b[0;32m--> 446\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_conv_forward\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mweight\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbias\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/nn/modules/conv.py:442\u001b[0m, in \u001b[0;36mConv2d._conv_forward\u001b[0;34m(self, input, weight, bias)\u001b[0m\n\u001b[1;32m 438\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpadding_mode \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mzeros\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 439\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m F\u001b[38;5;241m.\u001b[39mconv2d(F\u001b[38;5;241m.\u001b[39mpad(\u001b[38;5;28minput\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reversed_padding_repeated_twice, mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpadding_mode),\n\u001b[1;32m 440\u001b[0m weight, bias, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstride,\n\u001b[1;32m 441\u001b[0m _pair(\u001b[38;5;241m0\u001b[39m), \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdilation, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgroups)\n\u001b[0;32m--> 442\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mF\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconv2d\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mweight\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbias\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstride\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 443\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpadding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdilation\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgroups\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(20):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " #print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # https://stackoverflow.com/questions/42704283/adding-l1-l2-regularization-in-pytorch\n", + " #to_cat = []\n", + " #for v in model.state_dict.values():\n", + " # flat = v.flatten()\n", + " # to_cat.append(flat)\n", + " #flat = torch.cat(to_cat, dim=0)\n", + " #loss = loss_fn(pred,y) + 0.02*torch.norm(flat, 2)\n", + " # Backpropagation\n", + " loss.backward()\n", + " #print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " optimizer.step()\n", + " optimizer.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " #print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "after 8: Accuracy: 67.3%, Avg loss: 1.200284 " + ] + } + ], + "metadata": { + "colab": { + "name": "learningrate.ipynb", + "provenance": [] + }, + "interpreter": { + "hash": "996934296aa9d79be6c3d800a38d8fdb7dfa8fe7bb07df178f1397cde2cb8742" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/random files/learningrate.ipynb b/random files/learningrate.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..8045caf05eac5aa85a81910fb935ed6467377488 --- /dev/null +++ b/random files/learningrate.ipynb @@ -0,0 +1,6547 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZMZYcW3itMzT", + "outputId": "f2970f7e-cf26-4a67-e8d3-29bcd1a11775" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2VftlLfttdT8", + "outputId": "48b47fdc-853b-4711-ae95-8c0e64510615" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "ft7BMl1LyWP6" + }, + "outputs": [], + "source": [ + "from torch import nn\n", + "import torch\n", + "import os\n", + "import json\n", + "import pickle\n", + "import numpy as np\n", + "import pywt\n", + "train_dir = \"../../\"\n", + "my_train_data = {\"x\": [], \"y\": []}" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<torch._C.Generator at 0x7f2f8c078db0>" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.manual_seed(13)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "hi0N5rB5xBWn" + }, + "outputs": [], + "source": [ + "if torch.cuda.is_available():\n", + " device = \"cuda\"\n", + "else:\n", + " device = \"cpu\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "6lO3uYsmxNYz", + "outputId": "b170b610-f21e-465d-fcd6-b7e6989e73e5" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'cpu'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "device" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "torch.set_num_threads(6)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Contents\n", + "* [CNN Model Training](#train)\n", + "* [Optimizer analysis](#optim)\n", + "* [FFT](#fft)\n", + "* [Wavelets](#wt)\n", + "* [FFT Training](#ffttrain)\n", + "* [Node_Training](#nodetraining)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CNN Model Training <a class=\"anchor\" id=\"train\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "9LpgzEw1s-xo" + }, + "outputs": [], + "source": [ + "# From Femnist.py\n", + "def read_file(file_path):\n", + " with open(file_path, \"r\") as inf:\n", + " client_data = json.load(inf)\n", + " print(\"loaded the data\")\n", + " return (\n", + " client_data[\"users\"],\n", + " client_data[\"num_samples\"],\n", + " client_data[\"user_data\"],\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QBu1kiw8s-xr" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "raw", + "metadata": { + "id": "jI3ixEN4s-xt", + "outputId": "ed969663-9e1e-4810-9507-52cdc426650a" + }, + "source": [ + "# From Femnist.py\n", + "for i in range(1):\n", + " cur_file = \"leaf/data/femnist/data/train/all_data_0_niid_0_keep_0_train_9.json\"\n", + " # test_file = \"leaf/data/femnist/data/test/all_data_0_niid_0_keep_0_test_9.json\"\n", + " # cur_file = test_file\n", + " clients, _, train_data = read_file(\n", + " os.path.join(train_dir, cur_file)\n", + " )\n", + " for cur_client in clients:\n", + " # self.clients.append(cur_client)\n", + " my_train_data[\"x\"].extend(train_data[cur_client][\"x\"])\n", + " my_train_data[\"y\"].extend(train_data[cur_client][\"y\"])\n", + " del train_data[cur_client]\n" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "wvHsSz8as-xw" + }, + "source": [ + "train_x = (\n", + " np.array(my_train_data[\"x\"], dtype=np.dtype(\"float32\"))\n", + " .reshape(-1, 28, 28, 1)\n", + " .transpose(0, 3, 1, 2)\n", + ")\n", + "train_y = np.array(my_train_data[\"y\"], dtype=np.dtype(\"int64\")).reshape(-1)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "K8X471SKs-xz", + "outputId": "cdf73c06-1323-4e76-850b-16324008d255" + }, + "source": [ + "len(train_y)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "EpWNELBrs-x0" + }, + "source": [ + "with open(train_dir+\"femnist.pkl\", \"wb\") as f:\n", + " pickle.dump({\"test_x\": train_x, \"test_y\": train_y}, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mAEASHr2s-x1" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "Am_XlcSSs-x3" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "evAd9ZvYs-x6" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "9_vIFakbs-x7", + "outputId": "3a8b546a-186f-4519-8c0b-e853986a8101" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856, 1, 28, 28)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_x\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "GPyZ2C8ws-x9" + }, + "outputs": [], + "source": [ + "NUM_CLASSES = 62\n", + "IMAGE_SIZE = (28, 28)\n", + "FLAT_SIZE = 28 * 28\n", + "PIXEL_RANGE = 256.0\n", + "import torch.nn.functional as F\n", + "\n", + "class CNN(nn.Module):\n", + " \"\"\"\n", + " Class for a CNN Model for FEMNIST\n", + "\n", + " \"\"\"\n", + "\n", + " def __init__(self):\n", + " \"\"\"\n", + " Constructor. Instantiates the CNN Model\n", + " with 28*28*1 Input and 62 output classes\n", + "\n", + " \"\"\"\n", + " super().__init__()\n", + " # 1.6 million params\n", + " self.conv1 = nn.Conv2d(1, 32, 5, padding=2)\n", + " self.pool = nn.MaxPool2d(2, 2)\n", + " self.conv2 = nn.Conv2d(32, 64, 5, padding=2)\n", + " self.fc1 = nn.Linear(7 * 7 * 64, 512)\n", + " self.fc2 = nn.Linear(512, NUM_CLASSES)\n", + "\n", + " def forward(self, x):\n", + " \"\"\"\n", + " Forward pass of the model\n", + "\n", + " Parameters\n", + " ----------\n", + " x : torch.tensor\n", + " The input torch tensor\n", + "\n", + " Returns\n", + " -------\n", + " torch.tensor\n", + " The output torch tensor\n", + "\n", + " \"\"\"\n", + " x = self.pool(F.relu(self.conv1(x)))\n", + " x = self.pool(F.relu(self.conv2(x)))\n", + " x = torch.flatten(x, 1)\n", + " x = F.relu(self.fc1(x))\n", + " x = self.fc2(x)\n", + " return x\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bCgW8ClBs-x_" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "oBGwcwZks-yA" + }, + "outputs": [], + "source": [ + "import os\n", + "from torch.utils.data import Dataset\n", + "\n", + "class FemnistDataset(Dataset):\n", + " def __init__(self, training, transform=None, target_transform=None):\n", + " if training:\n", + " with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)\n", + " self.data = train[\"train_x\"]\n", + " self.label = train[\"train_y\"]\n", + " else: \n", + " with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)\n", + " self.data = test[\"test_x\"]\n", + " self.label = test[\"test_y\"]\n", + " self.transform = transform\n", + " self.target_transform = target_transform\n", + "\n", + " def __len__(self):\n", + " return len(self.label)\n", + "\n", + " def __getitem__(self, idx):\n", + " return self.data[idx], self.label[idx]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "U3boC_N4s-yC" + }, + "outputs": [], + "source": [ + "from torch.utils.data import DataLoader" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "sJsrQXkEs-yD" + }, + "outputs": [], + "source": [ + "trainset = FemnistDataset(True)\n", + "testset = FemnistDataset(False)\n", + "\n", + "train_dataloader = DataLoader(trainset, batch_size=128, shuffle=True)\n", + "test_dataloader = DataLoader(testset, batch_size=128, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "id": "e65Izyv0s-yE" + }, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1487, -0.1003, 0.0990, -0.0245, -0.1023, 0.0974, -0.1139, -0.1425,\n", + " -0.1949, -0.0679, -0.0937, 0.0891, 0.0577, -0.1357, 0.0814, 0.1157,\n", + " -0.1997, -0.1665, -0.1546, 0.1150, 0.0895, -0.1049, -0.0980, -0.0980,\n", + " 0.0729, 0.1947, 0.0421, -0.0365, -0.1470, -0.1679, 0.0286, -0.0146])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "tensor([-0.0180, 0.0236, 0.1279, -0.1352, -0.1948, -0.0330, -0.1615, -0.0286,\n", + " -0.1762, 0.0040, 0.1570, -0.1069, -0.1074, -0.1417, -0.1171, 0.0359,\n", + " 0.1276, -0.1534, -0.1773, -0.1639, 0.1334, 0.0518, 0.0586, 0.1466,\n", + " 0.1283, 0.0443, -0.0982, -0.1739, -0.0061, 0.1047, -0.0291, 0.1525])" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "for p in model.parameters():\n", + " print(p.data.size())\n", + " p.data = torch.zeros(p.data.size())" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0.])" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "eqOXilqMs-yF", + "outputId": "06799a3b-983b-4f51-a7bd-a901c041bd05" + }, + "outputs": [], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(10):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "id": "4P-VA0vcs-yH" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"/results:128:\"+str(lr)+\".pkl\", \"wb\") as f:\n", + " pickle.dump(stats, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "641-b_VCvT2b", + "outputId": "cced38ab-5c04-45b2-faf4-e73327126159" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "F_OKqiiHs-yJ", + "outputId": "65786b88-05f4-42fa-a851-03397ef4457a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.1: [9. 3.69780584 5.50521373]\n", + "0.01: [ 9. 3.98475619 82.61967193]\n", + "0.005: [ 9. 0.51492128 85.40642722]\n", + "0.001: [ 9. 0.41047618 88.03829502]\n", + "0.0005: [ 9. 0.44351858 88.21025672]\n", + "0.0001: [ 9. 0.67233266 87.71754375]\n", + "1e-05: [ 9. 1.81167539 81.52570279]\n" + ] + } + ], + "source": [ + "lrs = [0.1, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00001]\n", + "for l in lrs:\n", + " with open(train_dir+\"/results:128:\"+str(l)+\".pkl\", \"rb\") as f:\n", + " res = pickle.load(f)\n", + " print(str(l)+\": \" + str(np.amax(res[\"test\"], axis=0)))#+ str(np.max(res[\"test\"]))\n", + " # print(str(l)+\": \" + str(res[\"test\"]))\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rADw-XkfKjOo", + "outputId": "06c54a2c-f7c2-4610-f879-3e1c2f98543f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.1: [[0, 3.6898819485246297, 4.914933837429111], [1, 3.695287103771977, 4.914933837429111], [2, 3.691172517592003, 5.505213732544667], [3, 3.6920483804158226, 4.967376059515824], [4, 3.6939517986755845, 5.505213732544667], [5, 3.6917366434742993, 4.914933837429111], [6, 3.695435837910811, 5.505213732544667], [7, 3.6978058357506574, 5.135679004817367], [8, 3.6948341036363623, 5.505213732544667], [9, 3.6921330658768343, 5.135679004817367]]\n", + "0.01: [[0, 0.5728003431500958, 81.8086468687115], [1, 0.5517885946725348, 82.61967193121532], [2, 3.984756194857093, 25.844258796268065], [3, 0.5739870879932797, 81.7476675407037], [4, 0.7832032613188912, 75.77779132873955], [5, 0.7142617320772638, 77.80474419171901], [6, 0.6602287095348103, 79.28654186230868], [7, 0.6738644539380036, 79.2719068235868], [8, 0.6469118589079138, 79.77071772669065], [9, 0.6788249858734946, 79.28898103542899]]\n", + "0.005: [[0, 0.4834194714537649, 83.79047502896519], [1, 0.466142692822562, 84.33928898103544], [2, 0.4559767278791776, 84.9515214342338], [3, 0.4488265364432298, 84.86493078846271], [4, 0.4554814101660307, 84.773461796451], [5, 0.5149212768315897, 83.05872309287152], [6, 0.4551808235472338, 84.86127202878224], [7, 0.4531376465992325, 85.06494298432831], [8, 0.4589428385362238, 84.83078236477834], [9, 0.4409179601951992, 85.40642722117202]]\n", + "0.001: [[0, 0.4104761779773254, 85.89670101835478], [1, 0.36889259526491536, 87.17604731995854], [2, 0.3517718464717292, 87.6992499542655], [3, 0.35526543692939927, 87.57607171168974], [4, 0.3493265717198808, 87.76266845539362], [5, 0.35079776836259874, 87.47362644063662], [6, 0.34534544340812845, 87.96268065125923], [7, 0.35734797465540874, 87.72608085858894], [8, 0.3524193228360457, 87.63339228001708], [9, 0.35447056082407136, 88.0382950179889]]\n", + "0.0005: [[0, 0.4435185831906085, 85.1039697542533], [1, 0.37539843543085405, 86.94310628696871], [2, 0.35873422210283473, 87.3797182755046], [3, 0.34818319706667605, 87.93097140069517], [4, 0.34545205666010914, 87.86633331300689], [5, 0.3371337376732536, 88.10415269223734], [6, 0.33852135716659976, 88.11512897127874], [7, 0.33852605533302293, 88.14074028904201], [8, 0.33997187332225476, 88.21025672297091], [9, 0.3402654077747311, 88.1968412708092]]\n", + "0.0001: [[0, 0.6723326555745278, 79.72437343740472], [1, 0.5084800024207409, 83.89901823281907], [2, 0.45863669222676995, 84.88932251966584], [3, 0.42524330169194946, 85.90767729739618], [4, 0.4028480564841242, 86.33575218001097], [5, 0.38621816764383715, 86.9126166229648], [6, 0.3782781209337544, 87.11506799195074], [7, 0.3759017101781045, 87.00530520153667], [8, 0.3668581307538772, 87.32117812061712], [9, 0.3569657983208967, 87.71754375266785]]\n", + "1e-05: [[0, 1.8116753936371826, 54.021586682114766], [1, 1.3575628893609724, 63.8148667601683], [2, 1.0996285610935432, 69.48716385145435], [3, 0.9349309672803477, 73.7788889566437], [4, 0.8294046315685635, 76.08878590157937], [5, 0.7614829346374863, 77.91938532837368], [6, 0.7032811826737176, 79.30727483383133], [7, 0.6657257149818349, 80.09024940545156], [8, 0.6363296165202226, 80.82931886090616], [9, 0.6094131586890139, 81.52570278675529]]\n" + ] + } + ], + "source": [ + "lrs = [0.1, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00001]\n", + "for l in lrs:\n", + " with open(train_dir+\"/results:128:\"+str(l)+\".pkl\", \"rb\") as f:\n", + " res = pickle.load(f)\n", + " # print(str(l)+\": \" + str(np.amax(res[\"test\"], axis=0)))#+ str(np.max(res[\"test\"]))\n", + " print(str(l)+\": \" + str(res[\"test\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HGpNYzG_s-yJ", + "outputId": "783622a5-249f-4dd8-d242-fc6dfa47443c" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using cache found in /home/jeffrey/.cache/torch/hub/pytorch_vision_v0.10.0\n" + ] + } + ], + "source": [ + "import torch\n", + "resnet = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uZFgT6wss-yL", + "outputId": "10f8fc51-abb7-4c2b-f608-85229f3de29d", + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11699132\n" + ] + } + ], + "source": [ + "total = 0\n", + "for i in resnet.state_dict().values():\n", + " total += i.flatten().size(dim=0)\n", + "print(total)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizer analysis <a class=\"anchor\" id=\"optim\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "id": "mRZYP5UNs-yL" + }, + "outputs": [], + "source": [ + "# internal state test\n", + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)\n", + "old = model.state_dict()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0877, -0.1623, -0.0757, -0.1486, 0.1212, 0.1070, 0.0221, -0.1306,\n", + " 0.0798, -0.1525, -0.0297, -0.1715, 0.1039, 0.0143, 0.0982, 0.0428,\n", + " -0.0983, -0.0698, 0.1894, 0.1400, 0.0139, -0.0640, 0.0410, -0.0332,\n", + " -0.0993, -0.0840, -0.1224, 0.0723, 0.1994, 0.0017, -0.1309, 0.0044])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "old[\"conv1.bias\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1695, 0.0365, 0.0043, -0.0058, 0.1130, 0.1614, -0.1921, 0.0229,\n", + " 0.1472, 0.0111, -0.1327, -0.0368, 0.0536, -0.0637, 0.1539, 0.1022,\n", + " 0.1948, -0.1443, 0.1046, 0.1746, 0.1998, -0.0572, 0.0675, -0.1533,\n", + " -0.1863, -0.0397, 0.1823, -0.0121, 0.0045, 0.0704, 0.1362, 0.1068])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.state_dict()[\"conv1.bias\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0877, -0.1623, -0.0757, -0.1486, 0.1212, 0.1070, 0.0221, -0.1306,\n", + " 0.0798, -0.1525, -0.0297, -0.1715, 0.1039, 0.0143, 0.0982, 0.0428,\n", + " -0.0983, -0.0698, 0.1894, 0.1400, 0.0139, -0.0640, 0.0410, -0.0332,\n", + " -0.0993, -0.0840, -0.1224, 0.0723, 0.1994, 0.0017, -0.1309, 0.0044])" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "old[\"conv1.bias\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'state': {},\n", + " 'param_groups': [{'lr': 0.0005,\n", + " 'betas': (0.9, 0.999),\n", + " 'eps': 1e-08,\n", + " 'weight_decay': 0,\n", + " 'amsgrad': False,\n", + " 'params': [0, 1, 2, 3, 4, 5, 6, 7]}]}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "optimizer.state_dict()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n", + "<class 'torch.nn.parameter.Parameter'>\n" + ] + } + ], + "source": [ + "for p in model.parameters():\n", + " print(type(p))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(optimizer.param_groups[0][\"params\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "ename": "IndexError", + "evalue": "list index out of range", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [19]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparam_groups\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\n", + "\u001b[0;31mIndexError\u001b[0m: list index out of range" + ] + } + ], + "source": [ + "optimizer.param_groups[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['params', 'lr', 'betas', 'eps', 'weight_decay', 'amsgrad'])" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "optimizer.param_groups[0].keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Parameter containing:\n", + "tensor([-0.0877, -0.1623, -0.0757, -0.1486, 0.1212, 0.1070, 0.0221, -0.1306,\n", + " 0.0798, -0.1525, -0.0297, -0.1715, 0.1039, 0.0143, 0.0982, 0.0428,\n", + " -0.0983, -0.0698, 0.1894, 0.1400, 0.0139, -0.0640, 0.0410, -0.0332,\n", + " -0.0993, -0.0840, -0.1224, 0.0723, 0.1994, 0.0017, -0.1309, 0.0044],\n", + " requires_grad=True)" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "optimizer.param_groups[0][\"params\"][1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# --> yes the optimizer values do not get updates" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "defaultdict(dict, {})" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "optimizer.state" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# optimizer.state is a dictionary that gets filled during the first step() call\n", + "# as keys it has the params and as values it has the internal state of the optimizer (first momentum, second momentum etc)\n", + "# stored the values in vals, they are from running the training loop" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(vals)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "vals_list = list(vals)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(vals_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'step': 69,\n", + " 'exp_avg': tensor([-1.4137e-03, -1.0432e-02, -5.7605e-03, -1.5292e-02, -1.1802e-02,\n", + " 1.1299e-03, 2.1533e-03, -9.7591e-03, -8.8733e-03, -4.7788e-03,\n", + " -1.9228e-03, -5.7594e-03, -5.4949e-05, -3.8590e-05, 1.3072e-04,\n", + " -7.8018e-03, -6.1446e-04, -2.9151e-03, -3.3301e-03, -2.0083e-03,\n", + " -3.0533e-03, -3.5316e-04, -8.1218e-03, 5.7864e-04, 5.8342e-04,\n", + " -1.1397e-02, -8.2111e-04, -6.8639e-03, -7.7449e-04, 1.0854e-04,\n", + " -4.7743e-05, -9.0613e-03]),\n", + " 'exp_avg_sq': tensor([9.6760e-06, 2.4495e-05, 8.1120e-06, 3.0419e-05, 1.0932e-05, 2.3003e-05,\n", + " 1.9296e-05, 1.5492e-05, 2.6551e-06, 1.1472e-05, 2.6787e-05, 9.0655e-05,\n", + " 8.7915e-11, 3.1380e-05, 4.9582e-06, 3.9729e-06, 7.5247e-06, 1.8417e-05,\n", + " 6.9078e-06, 2.9552e-05, 5.0895e-06, 1.6462e-06, 2.1158e-06, 2.8078e-06,\n", + " 2.5839e-06, 2.6732e-05, 2.0372e-05, 9.5084e-07, 2.0701e-06, 1.2862e-06,\n", + " 1.5106e-06, 2.5722e-05])}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vals_list[1] # entry for " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The most feasible solution would be to create a new optimizer and then \n", + "# vals = list(optimizer.state.values())\n", + "# create new optimizer\n", + "# for i, k in enmumerate(optimizer.param_groups[0][\"params\"]):\n", + "# optimizer.state[k] = vals[i]\n", + "# https://pytorch.org/docs/stable/_modules/torch/optim/adam.html#Adam\n", + "# https://pytorch.org/docs/stable/_modules/torch/optim/optimizer.html#Optimizer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## FFT <a class=\"anchor\" id=\"fft\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856, 1, 28, 28)" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_x\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5748.875" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "735856 / 128" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "weights = {}" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.124378 [ 0/735856]\n", + "loss: 1.539611 [64000/735856]\n", + "loss: 0.719579 [128000/735856]\n", + "loss: 0.685157 [192000/735856]\n", + "loss: 0.778637 [256000/735856]\n", + "loss: 0.493262 [320000/735856]\n", + "loss: 0.423785 [384000/735856]\n", + "loss: 0.531239 [448000/735856]\n", + "loss: 0.803173 [512000/735856]\n", + "loss: 0.498672 [576000/735856]\n", + "loss: 0.453685 [640000/735856]\n", + "loss: 0.355350 [704000/735856]\n", + "loss: 0.417364 [768000/735856]\n", + "loss: 0.462418 [832000/735856]\n", + "loss: 0.361217 [896000/735856]\n", + "loss: 0.484760 [960000/735856]\n", + "loss: 0.360997 [1024000/735856]\n", + "loss: 0.353997 [1088000/735856]\n", + "loss: 0.378490 [1152000/735856]\n", + "loss: 0.376164 [1216000/735856]\n", + "loss: 0.375268 [1280000/735856]\n", + "loss: 0.570408 [1344000/735856]\n", + "loss: 0.295247 [1408000/735856]\n", + "loss: 0.257762 [1472000/735856]\n", + "loss: 0.609368 [1536000/735856]\n", + "loss: 0.423437 [1600000/735856]\n", + "loss: 0.363265 [1664000/735856]\n", + "loss: 0.393251 [1728000/735856]\n", + "loss: 0.353971 [1792000/735856]\n", + "loss: 0.279443 [1856000/735856]\n", + "loss: 0.532804 [1920000/735856]\n", + "loss: 0.364327 [1984000/735856]\n", + "loss: 0.310962 [2048000/735856]\n", + "loss: 0.306962 [2112000/735856]\n", + "loss: 0.391289 [2176000/735856]\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "batch = 0\n", + "for e in range(3):\n", + " #training\n", + " for X, y in train_dataloader:\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " weight = {}\n", + " for k,v in model.state_dict().items():\n", + " weight[k] = v.clone()\n", + " \n", + " weights[str(batch)] = weight\n", + " batch += 1" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.2%, Avg loss: 0.367197 \n", + "\n" + ] + } + ], + "source": [ + "size = len(test_dataloader.dataset)\n", + "num_batches = len(test_dataloader)\n", + "model.eval()\n", + "test_loss, correct = 0, 0\n", + "with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + "test_loss /= num_batches\n", + "correct /= size\n", + "print(\"epoch:\")\n", + "print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + "stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['0', '500', '1000', '1500', '2000', '2500', '3000', '3500', '4000', '4500', '5000', '5500', '6000', '6500', '7000', '7500', '8000', '8500', '9000', '9500', '10000', '10500', '11000', '11500', '12000', '12500', '13000', '13500', '14000', '14500', '15000', '15500', '16000', '16500', '17000'])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weights.keys()" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "with open(\"vecs.pkl\", \"wb\") as f:\n", + " \n", + " json.dump(weights, f)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* 1d on flattend\n", + "* 1d on layers\n", + "* nd on layers" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "# working on the random initialization\n", + "flat = []\n", + "for v in weights[\"17000\"].values():\n", + " flat.append(v.flatten())\n", + "conc = torch.cat(flat)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1690046" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(conc)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1440, -0.0482, 0.2070, -0.2534, -0.2413, 0.0336, -0.2401, 0.2761,\n", + " 0.2361, -0.2687])" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "conc[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "import torch.fft as fft" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1690046" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft = fft.fft(conc)\n", + "len(flat_fft)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "845024" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft = fft.rfft(conc)\n", + "len(flat_fft)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-3912.2754+0.0000j, -685.3215+117.2780j, -718.2836-68.4478j,\n", + " ..., 33.0949-6.6868j, 49.2176+6.2663j,\n", + " -9.9980+0.0000j])" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "reverse = fft.irfft(flat_fft)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1440, -0.0482, 0.2070, -0.2534, -0.2413, 0.0336, -0.2401, 0.2761,\n", + " 0.2361, -0.2687])" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.0004)" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc - reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "top10 = torch.zeros(flat_fft.size(dim=0), dtype = torch.cfloat)\n", + "top10[0:84502] = flat_fft[0:84502]" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-3912.2754+0.0000j, -685.3215+117.2780j, -718.2836-68.4478j,\n", + " ..., 0.0000+0.0000j, 0.0000+0.0000j,\n", + " 0.0000+0.0000j])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top10" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "reverse_t10 = fft.irfft(top10)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0439, -0.0400, -0.0357, -0.0312, -0.0269, -0.0229, -0.0193, -0.0162,\n", + " -0.0134, -0.0109])" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_t10[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(40.2866)" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_t10 - reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "d10 = torch.zeros(flat_fft.size(dim=0), dtype = torch.cfloat)\n", + "d10[-84502:] = flat_fft[-84502:]" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "reverse_d10 = fft.irfft(d10)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0026, 0.0042, -0.0056, 0.0065, -0.0065, 0.0053, -0.0029, -0.0008,\n", + " 0.0059, -0.0120])" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_d10[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(43.7672)" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_d10 - reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "rand = torch.rand(conc.size(dim=0))" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(754.6744)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(rand - reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(29442.5273)" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_d10 - reverse, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(27450.3555)" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_t10 - reverse, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(30432.2695)" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-3912.2754+0.0000j, -685.3215+117.2780j, -718.2836-68.4478j,\n", + " ..., 33.0949-6.6868j, 49.2176+6.2663j,\n", + " -9.9980+0.0000j])" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([3912.2754, 695.2839, 721.5375, ..., 33.7637, 49.6149,\n", + " 9.9980])" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat_fft.abs()" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(torch.arange(0,len(conc)), conc, '.')\n", + "plt.title('Parameter Values') \n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.draw()\n", + "plt.savefig(\"Parameter_Values.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYsAAAEWCAYAAACXGLsWAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAv/0lEQVR4nO3de5wcVZ338c93JgkQCJCEAQMhJIFwCa4GGCGIKyiCwIKwihpkJSgssouurOuusOsjiPosuiKuNyACAj5cFdGIKETkIgiBDIRLApEhJCQhhJAbIYEkk/k9f9TpSaUz092TTM90Zr7v16teU3XqVNWp6pr+dZ1TdUoRgZmZWSl1PV0AMzOrfQ4WZmZWloOFmZmV5WBhZmZlOViYmVlZDhZmZlaWg0UfIGmkpJDUr4K8Z0p6qDvKVaYcMyQd1dPlsL5F0t9KmtXT5ahFDhY1RtIcSWsl7VKU/mT6wh/ZQ0XLB503c8NT1dhWRBwYEfd3xbokHSWptajcv+2KdW9NJF0saV3a/+WS/iLp8J4uV1dJn/P8Ti4TkvYpTEfEnyNiv64v3dbPwaI2vQScVpiQ9DfAwJ4rziZ2jogd0vDurlxxJVc/m7n8K7ky7xARJ3X1trcSt0bEDsAuwH3AL7p6A8r4u6WX8Qdam34OnJGbngjckM8gaSdJN0haLGmupK8W/kEl1Uv6rqTXJc0G/q6dZa+RtFDSAknflFS/JQWWtLukyZKWSmqW9I+5eddJ+mZueqNfgOlq6iuSngZWSeqX0j6U5tdJukDSi5KWSLpN0pA0r3C1c5akl4E/daLMZ0p6WNLlkpYAF0vaJh27lyUtknSlpO1yy/x7Om6vSPps/peppPslnV20/ody0/tLmpKO0SxJnyg6Rj+W9DtJKyVNlbR3bv6BuWUXSfpPSe+QtFrS0Fy+g9M50b/UvkdEC3AjsIekhrRsh+dF7lj9SNIKSc9LOjq33fslfUvSw8BqYHSZ/T1B0sy0rwskfTk370RJ07Xh6udduXlzJH1Z0tOpHLdK2lbS9sDvgd214epxd0mHSnokrWthKv+AtK4H02qfSvk/2c65eUDat+XKqkY/Uuln1ts4WNSmR4Ed04laD0wA/l9Rnh8COwGjgSPJgstn0rx/BE4EDgIagVOLlr0OaAH2SXmOBc5my9wCzAd2T9v7v5I+2InlTyMLajunL7K8LwCnkO3n7sAy4MdFeY4EDgA+3MlyHwbMBnYDvgVcCuwLjCM7PnsAXwOQdBzwZeAYYAzwoUo3kr7MpgA3AbuSfaY/kTQ2l20C8HVgMNCcyoOkQcAfgT+Q7f8+wL0R8SpwP/CJ3Do+DdwSEevKlGcA2TmzhOx4Qvnz4jDgRbKrkouAXxWCdm7b5wCDgMVl9vca4HMRMQh4JynISzoIuBb4HDAUuAqYLGmb3HY+ARwHjALeBZwZEauA49n4CvIVYD3wr6nMhwNHA/8MEBHvT+t7d8p/a9Ex6g/8Frgn7cMXgBsl5aup2v3MeqWI8FBDAzCH7Evoq8B/k/1TTAH6AQGMBOqBtcDY3HKfA+5P438Czs3NOzYt24/sS3ENsF1u/mnAfWn8TOChDso2Mq1neW74MrAn2T/loFze/wauS+PXAd/MzTsKmF+0z59t7zik8eeAo3PzhgHr0v4UyjS6xDE9CmgtKvcn0r6+nMsnYBWwdy7tcOClNH4tcGlu3r5p2/uk6fuBs3Pz244l8Engz0Xlugq4KHeMrs7NOwF4Pvf5PNnBvn0SeDiN1wOvAod2kPfidN4sT5/XEuCoNK+S8+IVQLn5jwGfzu37JUXlKrW/L5OdszsW5bkC+EZR2izgyNx58Q+5ed8BrmzvvOrgGJwP3JGbbvv8itcB/G06nnW5+TcDF5f7zHrj0BfqaLdWPwceJPv1dEPRvF2A/sDcXNpcsl/BkP36nFc0r2CvtOxCSYW0uqL85ewSuV//kg4DlkbEyqJtNnZinaW2vxdwh6TWXNp6si+4SpaH7Bfn8HyCpDOLlmsgaxtqyh0bkX0JQ3Zcm3L588e1nL2AwyQtz6X1I/ucC17Nja8Gdkjje5L9om/Pb4ArJY0C9gNWRMRjJcpxW0T8g7IbKG4HDiH7oq/kvFgQ6VsxmUt2TAryecvt78fIfhBdqqz68YKIeCQtN1HSF3LLDSjaTvFxys/biKR9ge+RnYsDUxmaOspfZHdgXkTkz7v8/1l7ZdmBXsrBokZFxFxJL5H9WjmraPbrZL+s9wJmprQRwII0vpDsC4bcvIJ5ZL8gN/rC30KvAEMkDcoFjHx5VrFxA/072llHqe6P55FdeTxcPEMb7g7b3O6T88u9DrwFHBgRC9rJW+q4Qun9nAc8EBHHbEYZ55FVd2wiIt6WdBvwD8D+bBx8OhQRr0s6B5gm6SYqOy/2kKRcwBgBTM6vtqjMHe5vRDwOnJyqej4P3EZ2bOcB34qIzanOae8cuAJ4EjgtIlZKOp9Nq2U78gqwp6S6XMAYAfx1M8q21XObRW07C/hgZPWxbSJiPdk/17ckDZK0F/AlNrRr3Ab8i6ThkgYDF+SWXUhWB3uZpB2VNR7vLenIzS1kRMwD/gL8d2psfFcqe6E804ETJA2R9A6yqoDOuJJsX/cCkNQg6eTNLW9H0hfCT4HLJe2atrWHpEI7yG3AmZLGShpIVm+fNx34qKSByhq980H+TmBfSZ+W1D8N75F0QAVFuxMYJul8ZQ3wg9LVXMENZNVEH6HCYJH2dxZwN/AfFZ4Xu5KdV/0lfZysjeiuEmVud38lDZB0uqSdImtbeYOsmhCy43+upMOU2V7S36V2m3IWAUMl7ZRLG5TW/6ak/YF/ameZ0R2sbyrZ1cJ/pPIfBZxE1j7X5zhY1LCIeDEipnUw+wtkv2RnAw+RNSRem+b9lOxL4CngCeBXRcueQXZpP5OscfOXZO0AW+I0svaDV4A7yOqm/5jm/TyVZQ7ZF9Kt7Sxfyv+S/YK9R9JKshsADiu9yGb7CllD5aOS3iBrWN4PICJ+D3yfrE2omU3vvLqcrE1gEXA92d1GpGVXkrUdTSA7Rq8C3wa2oYy07DFkX1SvAi8AH8jNf5jsy/aJiOhM1RjA/wDnpOBY7ryYStaw/zpZQ+6pEbGkRJlL7e+ngTnpGJ8LnJ6Wm0Z2g8aPUhmayQJhWRHxPFmbwux099LuZG1qnwJWkv1fFJ97FwPXp/yfKFrfWrJjfnza558AZ6Tt9DnauArSzDpDUgBjIqK5h8vxJ+CmiLi6Sus/k6zx/n3VWL/VPrdZmG3lJL0HOBjo8qo5swJXQ5ltxSRdT1ZVdn7R3WhmXcrVUGZmVpavLMzMrKxe2Waxyy67xMiRI3u6GGZmW5WmpqbXI6KhvXm9MliMHDmSadM6uuPUzMzaI6nDW69dDWVmZmVVPVgo6y77SUl3pulRqSvfZmXdCxe6C94mTTen+SNz67gwpc/KPU1rZmbdpDuuLL5I1mtowbeByyNiH7InNAtdIpwFLEvpl6d8pC6NJwAHkvXA+hNt4bsXzMysc6oaLCQNJ3tHwdVpWsAHyboRgKxLhFPS+MlpmjT/6JT/ZLL++ddExEtkj/8fWs1ym5nZxqp9ZfF94D/Y0EnYUGB5rlfL+Wzo7ncPUhfHaf6KlL8tvZ1l2kg6R9I0SdMWL17cxbthZta3VS1YSDoReC0iKu07fotExKSIaIyIxoaGdu/8MjOzzVTNW2ePAD4i6QRgW2BHst5Dd5bUL109DGfDOw8WkPVnP19SP7JXhi7JpRfkl+lyTXOX8ejsJYwfPZRD9hpcrc2YmW1VqnZlEREXRsTwiBhJ1kD9p4g4HbiPDS8fmUj2pi/IuqCemMZPTfkjpU9Id0uNIusiudSbwDZb09xlnH71o1x2zyxOv/pRmuYuK7+QmVkf0BPPWXwF+JKkZrI2iWtS+jVkLy5pJnuRzwUAETGD7KUzM8leWH9eevlPl3t09hLWtrTSGrCupZVHZ7fbVb+ZWZ/TLU9wR8T9ZO/5JSJm087dTBHxNvDxDpb/FtnLVqpq/OihDOhXx7qWVvr3q2P86KHV3qSZ2VahV3b3sbkO2WswN5493m0WZmZFHCyKHLLXYAcJM7Mi7hvKzMzKcrAwM7OyHCzMzKwsBwszMyvLwcLMzMpysDAzs7IcLMzMrCwHCzMzK8vBwszMynKwMDOzshwszMysLAcLMzMry8HCzMzKcrAwM7OyqhYsJG0r6TFJT0maIenrKf06SS9Jmp6GcSldkn4gqVnS05IOzq1roqQX0jCxg02amVmVVPN9FmuAD0bEm5L6Aw9J+n2a9+8R8cui/MeTvV97DHAYcAVwmKQhwEVAIxBAk6TJEeEXZJuZdZOqXVlE5s002T8NUWKRk4Eb0nKPAjtLGgZ8GJgSEUtTgJgCHFetcpuZ2aaq2mYhqV7SdOA1si/8qWnWt1JV0+WStklpewDzcovPT2kdpRdv6xxJ0yRNW7x4cVfviplZn1bVYBER6yNiHDAcOFTSO4ELgf2B9wBDgK900bYmRURjRDQ2NDR0xSrNzCzplruhImI5cB9wXEQsTFVNa4CfAYembAuAPXOLDU9pHaWbmVk3qebdUA2Sdk7j2wHHAM+ndggkCTgFeDYtMhk4I90VNR5YERELgbuBYyUNljQYODalmZlZN6nm3VDDgOsl1ZMFpdsi4k5Jf5LUAAiYDpyb8t8FnAA0A6uBzwBExFJJ3wAeT/kuiYilVSy3mZkVUUSpG5S2To2NjTFt2rSeLoaZ2VZFUlNENLY3z09wm5lZWQ4WZmZWloOFmZmV5WBhZmZlOViYmVlZDhZmZlaWg4WZmZXlYGFmZmU5WJiZWVkOFmZmVpaDhZmZlVU2WEjaV9K9kp5N0++S9NXqF83MzGpFJVcWPyV7YdE6gIh4GphQzUKZmVltqSRYDIyIx4rSWqpRGDMzq02VBIvXJe0NBICkU4GFVS2VmZnVlEpefnQeMAnYX9IC4CXgH6paKjMzqyllrywiYnZEfAhoAPaPiPdFxJxyy0naVtJjkp6SNEPS11P6KElTJTVLulXSgJS+TZpuTvNH5tZ1YUqfJenDm7uzZma2ecpeWUj6WtE0ABFxSZlF1wAfjIg3JfUHHpL0e+BLwOURcYukK4GzgCvS32URsY+kCcC3gU9KGkvWoH4gsDvwR0n7RsT6zuyomZltvkraLFblhvXA8cDIcgtF5s002T8NAXwQ+GVKvx44JY2fnKZJ849WFplOBm6JiDUR8RLZO7oPraDcZmbWRcpeWUTEZflpSd8F7q5k5ZLqgSZgH+DHwIvA8ogo3E01H9gjje8BzEvbbJG0Ahia0h/NrTa/TH5b5wDnAIwYMaKS4pmZWYU25wnugcDwSjJGxPqIGJfyHwrsvxnbq0hETIqIxohobGhoqNZmzMz6pEraLJ4h3TYL1JM1dJdrr9hIRCyXdB9wOLCzpH7p6mI4sCBlWwDsCcyX1A/YCViSSy/IL2NmZt2gkiuLE4GT0nAssHtE/KjcQpIaJO2cxrcDjgGeA+4DTk3ZJgK/SeOT0zRp/p8iIlL6hHS31ChgDFD8kKCZmVVRh1cWkoak0ZVFs3aUREQsLbPuYcD1qd2iDrgtIu6UNBO4RdI3gSeBa1L+a4CfS2oGlpK6FImIGZJuA2aSPTl+nu+EMjPrXsp+vLczQ3qJrPpJ7cyOiBhdzYJticbGxpg2bVpPF8PMbKsiqSkiGtub1+GVRUSMql6RzMxsa1JJdx9IGkzWVrBtIS0iHqxWoczMrLZUcjfU2cAXye5Cmg6MBx4he7jOzMz6gEruhvoi8B5gbkR8ADgIWF7NQpmZWW2pJFi8HRFvQ9bZX0Q8D+xX3WKZmVktqaTNYn56XuLXwBRJy4C51SyUmZnVlkr6hvr7NHpxegp7J+APVS2VmZnVlEoauH9A1uvrXyLigW4ok5mZ1ZhK2iyagK9KelHSdyW1+8CGmZn1XpW8Ke/6iDiB7I6oWcC3Jb1Q9ZKZmVnN6EwX5fuQdTG+F/B8dYpjZma1qGywkPSddCVxCfAM0BgRJ1W9ZGZmVjMquXX2ReDwiHi92oUxM7PaVMmts1d1R0HMzKx2bc5rVc3MrI9xsDAzs7IqaeC+TNKBnV2xpD0l3SdppqQZkr6Y0i+WtEDS9DSckFvmQknNkmZJ+nAu/biU1izpgs6WxczMtkwlDdzPAZMk9QN+BtwcESsqWK4F+LeIeELSIKBJ0pQ07/KI+G4+s6SxZK9SPRDYHfijpH3T7B+TvcN7PvC4pMkRMbOCMpiZWReo5KG8qyPiCOAMYCTwtKSbJH2gzHILI+KJNL6SLOjsUWKRk8m6FVkTES8BzcChaWiOiNkRsRa4JeU1M7NuUlGbhaR6sgfy9gdeB54CviTplgqXH0n2HoypKenzkp6WdG16Cx9kgWRebrH5Ka2jdDMz6yaVtFlcTvbE9gnA/42IQyLi2+nBvIMqWH4H4Hbg/Ih4A7gC2BsYBywELtv84m+0nXMkTZM0bfHixV2xSjMzSyq5sngaGBcRn4uIx4rmHVpqQUn9yQLFjRHxK4CIWBQR6yOiFfhpbh0LgD1ziw9PaR2lbyQiJkVEY0Q0NjQ0VLBbZmZWqUqCxXJyDeGSdpZ0CkCphm5JAq4BnouI7+XSh+Wy/T3wbBqfDEyQtI2kUcAY4DHgcWCMpFGSBpA1gk+uoNxmZtZFKrkb6qKIuKMwERHLJV1E9ua8Uo4APg08I2l6SvtP4DRJ44AA5gCfS+udIek2YCbZnVTnRcR6AEmfB+4G6oFrI2JGJTtnZmZdo5Jg0d7VRyXdhDwEqJ1Zd5VY5lvAt9pJv6vUcmZmVl2VVENNk/Q9SXun4XtkL0QyM7M+opJg8QVgLXBrGtYA51WzUGZmVlsqqU5aBbiLDTOzPqxssEhdbnyZ7OnttvwR8cHqFcvMzGpJJQ3cvwCuBK4G1le3OGZmVosqCRYtEXFF1UtiZmY1q5IG7t9K+mdJwyQNKQxVL5mZmdWMSq4sJqa//55LC2B01xfHzMxqUSV3Q43qjoKYmVntqqTX2YGSvippUpoeI+nE6hfNzMxqRSVtFj8jeyjvvWl6AfDNqpXIzMxqTiXBYu+I+A6wDiAiVtN+n09mZtZLVRIs1krajqxRG0l7k3X5YWZmfURFXZQDfwD2lHQjWdfjZ1azUGZmVlsquRtqiqQngPFk1U9fjIjXq14yMzOrGZX0DfX+NLoy/R0riYh4sHrFMjOzWlJJNVT+Ybxtyd6Z3QS4I0Ezsz6ibAN3RJyUG44B3gksK7ecpD0l3SdppqQZkr6Y0odImiLphfR3cEqXpB9Iapb0tKSDc+uamPK/IGliR9s0M7PqqORuqGLzgQMqyNcC/FtEjCVr7zhP0liyd2PcGxFjgHvZ8K6M44ExaTgHuAKy4ELWyH4Y2VXNRYUAY2Zm3aOSNosfkm6bJQsu44Anyi0XEQuBhWl8paTngD2Ak4GjUrbrgfuBr6T0GyIigEcl7SxpWMo7JSKWpvJMAY4Dbq5kB83MbMtV0mYxLTfeAtwcEQ93ZiOSRgIHAVOB3VIgAXgV2C2N7wHMyy02P6V1lF68jXPIrkgYMWJEZ4pnZmZlVHLr7PVbsgFJOwC3A+dHxBvShoe/IyIkRYcLd0JETAImATQ2NnbJOs3MLFNJNdQzbKiG2mgW2ff9u0os258sUNwYEb9KyYskDYuIhama6bWUvgDYM7f48JS2gA3VVoX0+8uV28zMuk4lDdy/J3uC+/Q03JWGE4GTOlpI2SXENcBzEfG93KzJbHhHxkTgN7n0M9JdUeOBFam66m7gWEmDU8P2sSnNzMy6SSVtFsdExEG56QskPRERF3S4ROYI4NPAM5Kmp7T/BC4FbpN0FjAX+ESadxdwAtAMrAY+AxARSyV9A3g85buk0NhtZmbdo5JgIUlHFBq1Jb2Xyp7PeIiOe6c9up38AZzXwbquBa6toKxmZlYFlQSLs4BrJe2UppcDn61aiczMrOZUcjdUE/DuQrCIiBVVL5WZmdWUSl6rupuka4BbImKFpLGpvcHMzPqISu6Guo7s7qPd0/RfgfOrVB4zM6tBlQSLXSLiNqAVICJagPVVLZWZmdWUSoLFKklD2fBa1fGA2y3MzPqQSu6G+hLZA3N7S3oYaABOrWqpzMysppQMFpLqgSPTsB/ZcxOzImJdN5TNzMxqRMlqqIhYD5wWES0RMSMinnWgMDPreyqphnpY0o+AW4FVhcSIKPtOCzMz6x0qCRbj0t9LcmmB38FtZtZndBgsJH0xIv4X+D+pnyczM+ujSrVZfCb9/UF3FMTMzGpXqWqo5yS9AOwu6elcetmXHpmZWe/SYbCIiNMkvYOsq4+PdF+RzMys1pRs4I6IV4F3d1NZzMysRlXS3cdmkXStpNckPZtLu1jSAknT03BCbt6FkpolzZL04Vz6cSmtWVK5t/OZmVkVVC1YkPVWe1w76ZdHxLg03AUgaSwwATgwLfMTSfXpCfIfA8cDY4HTUl4zM+tGFQcLSQM7s+KIeBCo9F3ZJ5O9L2NNRLxE9h7uQ9PQHBGzI2ItcEvKa2Zm3aiSlx+9V9JM4Pk0/W5JP9mCbX5e0tOpmmpwStsDmJfLMz+ldZTeXjnPkTRN0rTFixdvQfHMzKxYJVcWlwMfBpYARMRTwPs3c3tXAHuTPRW+ELhsM9eziYiYFBGNEdHY0NDQVas1MzMq6+6DiJgnKZ+0WS8/iohFhXFJPwXuTJMLgD1zWYenNEqkm5lZN6nkymKepPcCIam/pC8Dz23OxiQNy03+PVC4U2oyMEHSNpJGAWOAx4DHgTGSRkkaQNYIPnlztm1mZpuvkiuLc4H/JWsrWADcA/xzuYUk3QwcBewiaT5wEXCUpHFkHRHOAT4HEBEzJN0GzARagPNS9+hI+jzZg4H1wLURMaPy3TMzs66giCidQToiIh4ul1ZLGhsbY9q0aT1dDDOzrYqkpohobG9eJdVQP6wwzczMeqlSXZQfDrwXaJD0pdysHcmqhMzMrI8o1WYxANgh5RmUS38DOLWahTIzs9pSqtfZB4AHJF0XEXO7sUxmZlZjKrkb6jpJm7SCR4Rfq2pm1kdUEiy+nBvfFvgY2e2tZmbWR5QNFhHRVJT0sKTHqlQeMzOrQWWDhaQhuck64BBgp6qVyMzMak4l1VBNZE9ci6z66SXgrGoWyszMaksl1VCjuqMgZmZWu0o9lPfRUgtGxK+6vjhmZlaLSl1ZnFRiXgAOFmZmfUSph/I+050FMTOz2lXJa1V3kvS9witLJV0myXdDmZn1IZX0OnstsBL4RBreAH5WzUKZmVltqeTW2b0j4mO56a9Lml6l8piZWQ2q5MriLUnvK0xIOgJ4q9xCkq6V9JqkZ3NpQyRNkfRC+js4pUvSDyQ1S3pa0sG5ZSam/C9Imti53TMzs65QSbD4J+DHkuZImgv8iOxVq+VcBxxXlHYBcG9EjAHuTdMAx5O9d3sMcA5wBbQ9PX4RcBhwKHBRIcCYmVn3qeShvOnAuyXtmKbfqGTFEfGgpJFFySeTvZcb4HrgfuArKf2GyN7x+qiknSUNS3mnRMRSAElTyALQzZWUwczMukYld0N9MQWKlcD3JD0h6djN3N5uEbEwjb8K7JbG9wDm5fLNT2kdpbdXznMKd2wtXrx4M4tnZmbtqaQa6rPpauJYYCjwaeDSLd1wuorY5D0ZW7C+SRHRGBGNDQ0NXbVaMzOjsmCh9PcEsqqiGbm0zlqUqpdIf19L6QuAPXP5hqe0jtLNzKwbVRIsmiTdQxYs7pY0CGjdzO1NBgp3NE0EfpNLPyPdFTUeWJGqq+4GjpU0ODVsH5vSzMysG1XynMVZwDhgdkSsljQUKNsViKSbyRqod5E0n+yupkuB2ySdBcwle8gP4C6yYNQMrC6sPyKWSvoG8HjKd0mhsdvMzLqPsqaDMpmyHmjfR9bG8FBE3FHtgm2JxsbGmDZt2mYt2zR3GY/OXsL40UM5ZC/fpWtmfYekpohobG9eJW/K+wmwDxtuV/2cpA9FxHldWMaa0DR3Gadf/ShrW1oZ0K+OG88e74BhZkZl1VAfBA5Idy8h6XpgZlVL1UMenb2EtS2ttAasa2nl0dlLHCzMzKisgbsZGJGb3hN4oTrF6VnjRw9lQL866gX9+9UxfvTQni6SmVlNKPWmvN+StVEMAp6T9FiaPgx4rHuK170O2WswN5493m0WZmZFSlVDfbfEvC57mK7WHLLXYAcJM7Mipd6U90B76akH2tOAB6tVKDMzqy2VNHAj6SDgU8DHgZeA26tZqJ7kW2fNzDZVqs1iX7IriNOA14FbyZ7L+EA3la3b+dZZM7P2lbob6nmy22ZPjIj3RcQPgfXdU6yekb91ds26Vr7/x7/SNHdZTxfLzKzHlaqG+igwAbhP0h+AW9j8DgS3CoMHDqA1Nd0H8NALrzN19hI+3rgnHz14eLtXGa62MrO+oMMri4j4dURMAPYH7gPOB3aVdMUWvM+ipj37yoqNpgNYuz64aerLnH71o5tcZRSqrS67Z1a7883MeouyD+VFxKqIuCkiTiLrIvxJsrfb9TodXTYFG57ozmvviW8zs96okie420TEsvSSoaOrVaCedODuO200fejIwSWf6PYT32bWV1R062xfsWz12rZxAUfutytfOf6ADtsk/MS3mfUVDhY5gwcOaBuPoumO+IlvM+sLHCxyihu475v1GpfcOcPPXZhZn9epNouuImmOpGckTZc0LaUNkTRF0gvp7+CULkk/kNQs6WlJB1etXEXTz8xf7gZsMzN6KFgkH4iIcbm3Ml0A3BsRY4B70zTA8cCYNJwDXFGtAn304OEM6LfhkCx6Yw2tAXVuwDazPq4ng0Wxk4Hr0/j1wCm59Bsi8yiws6Rh1SjAIXsN5uKTDmTk0IGIrN2iDjhin13aqqCa5i7jx/c1+5kKM+tTeqrNIoB7JAVwVURMAnaLiIVp/qvAbml8D2Bebtn5KW0hXaxp7jIuuXMGa9a1ZoFCMKBfHed/aN+2QOG+o8ysL+qpYPG+iFggaVdgiqTn8zMjIlIgqZikc8iqqRgxYkSZ3O17dPYS3l7X2jY9umEHvv2xd7UFBL921cz6qh6phoqIBenva8AdwKHAokL1Uvr7Wsq+gOxVrgXDU1rxOidFRGNENDY0NGxWuV5YtHKj6ebX3uSqB15sq3LyQ3hm1ld1e7CQtL2kQYVx4FjgWWAyMDFlmwj8Jo1PBs5Id0WNB1bkqqu61PR5yzdJu2fmorZ+nwoP4X3p2P1cBdUN3D5kVjt6ohpqN+AOSYXt3xQRf5D0OHCbpLOAucAnUv67gBOAZmA18JlqFWzEkIHMWbJ6k/S317Vy3o1N/MvR+/Kpw0Y4SHQDtw+Z1ZZuDxYRMRt4dzvpS4BN+pyKiADO64aiseKtdR3Oe/WNNfznHc/w8pJVDNquv7v3qDK3D5nVFj/BnbPrjtsCK0rmuerB2QDU14lLTn4n+71jkPuGqoJC+9C6lla3D5nVAAeLnA/stytTZi4qmadwi1ZLa/B/fv0M9fV1tKx3VUlXcyeNZrXFwSJn2eq1bQ/jVaI1oLWldaP3XfhLreu4k8bK+Y2NVm0OFjmdreqoqwMQEeGqkirwF2BlfDOAdQcHi5yfPzKn4qsKgPWtAEGd4MzDR/oftIzOfPn7C7ByvhnAukMt9Q3V4373TOnHN+oE++y6wybprQFX/Xl2xc8D9IbnBy696zmO+p/7uPSu5yrK3zR3GRMmPcL/3D2LCZMeKbvvfmVt5fywqHUHX1nkrFtf+rqiNeDF195sd14EfPv3z3Hbue8tuY6mucv45KRHaFkf9KsXt55z+Fb3K/DSu57jynRXWOHvBSccUHKZqx54se34rlsffOX2pzfqSqVY/gsv6HwVYV/imwGsO/jKopNKhZNpFVwpXPXAi7SkL82W9cFVD7zYRSXrPjc99nLJ6fZMnbPxlUHza2/yyase4aapG5YtXHHdNPVlvnrHM7Smg90aWRVhb7gi6yo+FtbdfGXRhVrbiSTF9fSPzVm60fxFb7zdTaXbfMX7sHpty0bzC9M3TX2Z3z+7kOPfOWyT509WvtWyyXpbWoP/Sg86jhi6PV/7zbOsb412A/Kvp7/CXc++6tuU2bQ952snHsjFv53R9kzKzf84HqDt+OfH++oxsy3nYNHF9r7wdzQM2obxo4eyYPlbPD4n++VXLxi9y/YsX73xU+JL3lzTNt40dxlXPvAir73xNp98zwg+ddjm9Z67Oc6/5Unu/+tijtq3ge9POGijMhU3NLe0brxsSyuccc1UHnzhdQD+nP4WDNqmvt1ACtmVWqEqq5y1acNrc20Y+S/Bnjx+1ZYP2L96Yn5bN/rrWlq59fGXNzo2X/nlU7y87C1a1rfSr04gOcjaFnOw6GLrI+sa5NfTX9kk/YXFqzbJP3/524z7+t1sv21/Fi5/q+1L9an5zwDwqcNGlLyLqHhe4QvzpcVvMrphBz535N5lvxzOv+XJtvIW/n5/wkHZ+z1+O6Ot2/ZCH1ntebAoQOStXLO+5PY7qzWyHoIv/+NfaVkf1NfBISMG8/icZW1XJU/N77hrlqa5y7j9ifkIOHD3nVi2em2X/+rOfy5Q/pd9R/kBbn9iPrdNm8f6tK9IbftZX1/XFigKmnPn2dr1QaHydM26Vm5/Yn7beeKrDesMZV0v9S6NjY0xbdq0Ti838oLfVaE0m69/vRg6cACvrtxw9XHu+0dzwQkHtH3h/bJpftuvxq+deCBf/fUzG/2Kr0tXNKMbduCo/Xbl2VdW8KeZi3h91RqGDx7IZZ8Yx4RJj2zSuN+ZhxO3BgK2H1CP6sTKtzetEgMY07A9U/7tqLbpwhfq4IEDuG/WayWvWIq/7D92xV/a5tUpC3D1gm+c8jcbBafzb3mSu55ZyNr1gVLe/EdR7nMYtE19p4PxXkMGMnfphg4zjx27G587cm+AtiD60YOHl/1h0luU26/C/JVvrWPGwjc4/p3DetVVa56kptyrrjee52CxQa0FC+sZew0ZyGsr3+btVNVTbMjA/uw5ZCCffM8IXl6yil9PX8CiN9Z0OrgOqFf65V+bDh2ZfXHOfn0Vq9eu5+1164n0TvqjD9gQYAoBtdQVWiWBpqM8+aBdyTYGDxzAs6+soHnRSta0tDJql+156fVVrG1p5eWlq1nT0so7d9+RYw58By8sWsnkp15pC+b77jaIV1a8xao16xmyfX8+etBwrntkzkYvRQOor4P9dhvEN075m7ZjkL+6Lw66lQakzgbirg7gDhYVcrAw23JDBvbnjbfXUSdRL7GuNWhJl7v968Xho4fy+JylbcF45+36EcCK3E0Q575/NI/MXsK8patZunrT3qAPHTmYBcvfYsmqtZt8kdea4h8F2/WvY0D/Ota1BHWw0dWugPekfUPiwGE7tlUlF4JQ86KVLF21lv71dfz1tTdpbQ3q68TZ7xvFG2taOrwyrISDRYUcLMyst7j9n97b6YBRKlj4OQszs17oU5Me6dL1OViYmfVCa7q4PWyrCRaSjpM0S1KzpAt6ujxmZn3JVhEsJNUDPwaOB8YCp0ka27OlMjPrO7aKYAEcCjRHxOyIWAvcApzcw2UyM+sztpZgsQcwLzc9P6W1kXSOpGmSpi1evLhbC2dm1tttLcGirIiYFBGNEdHY0NDQ08UxM+tVtpZgsQDYMzc9PKV1qTmX/l1Xr9LMrEd09ffZ1tKR4OPAGEmjyILEBOBT1diQA4aZ2aa2imARES2SPg/cDdQD10bEjB4ulplZn7FVBAuAiLgLuKuny2Fm1hdtLW0WZmbWgxwszMysLAcLMzMry8HCzMzK6pXvs5C0GJi7BavYBej4pdLm41Oaj09pPj6l9eTx2Ssi2n2quVcGiy0laVpHLwAxH59yfHxK8/EprVaPj6uhzMysLAcLMzMry8GifZN6ugA1zsenNB+f0nx8SqvJ4+M2CzMzK8tXFmZmVpaDhZmZleVgkSPpOEmzJDVLuqCny9PVJO0p6T5JMyXNkPTFlD5E0hRJL6S/g1O6JP0gHY+nJR2cW9fElP8FSRNz6YdIeiYt8wNJKrWNWiOpXtKTku5M06MkTU37c6ukASl9mzTdnOaPzK3jwpQ+S9KHc+ntnl8dbaMWSdpZ0i8lPS/pOUmH+/zZQNK/pv+tZyXdLGnbXnMORYSHrN2mHngRGA0MAJ4CxvZ0ubp4H4cBB6fxQcBfgbHAd4ALUvoFwLfT+AnA7wEB44GpKX0IMDv9HZzGB6d5j6W8Sssen9Lb3UatDcCXgJuAO9P0bcCENH4l8E9p/J+BK9P4BODWND42nTvbAKPSOVVf6vzqaBu1OADXA2en8QHAzj5/2o7NHsBLwHa5z/XM3nIO9fgBrpUBOBy4Ozd9IXBhT5eryvv8G+AYYBYwLKUNA2al8auA03L5Z6X5pwFX5dKvSmnDgOdz6W35OtpGLQ1kb2C8F/ggcGf6wnod6Fd8jpC9W+XwNN4v5VPxeVPI19H5VWobtTYAO6UvQxWl+/yJtmAxjywI9kvn0Id7yznkaqgNCh90wfyU1iulS96DgKnAbhGxMM16FdgtjXd0TEqlz28nnRLbqCXfB/4DaE3TQ4HlEdGSpvP703YM0vwVKX9nj1mpbdSaUcBi4Gepqu5qSdvj8weAiFgAfBd4GVhIdk400UvOIQeLPkjSDsDtwPkR8UZ+XmQ/Tap6P3V3bKOzJJ0IvBYRTT1dlhrWDzgYuCIiDgJWkVUJtemr5w9Aakc5mSyo7g5sDxzXo4XqQg4WGywA9sxND09pvYqk/mSB4saI+FVKXiRpWJo/DHgtpXd0TEqlD28nvdQ2asURwEckzQFuIauK+l9gZ0mFN0rm96ftGKT5OwFL6PwxW1JiG7VmPjA/Iqam6V+SBQ+fP5kPAS9FxOKIWAf8iuy86hXnkIPFBo8DY9JdBQPIGpwm93CZulS6s+Qa4LmI+F5u1mSgcEfKRLK2jEL6GemulvHAilQVcDdwrKTB6dfUsWR1pAuBNySNT9s6o2hd7W2jJkTEhRExPCJGkn32f4qI04H7gFNTtuJjU9ifU1P+SOkT0p0uo4AxZI227Z5faZmOtlFTIuJVYJ6k/VLS0cBMfP4UvAyMlzQwlb9wfHrHOdTTjUK1NJDdvfFXsjsO/quny1OF/Xsf2eX708D0NJxAVud5L/AC8EdgSMov4MfpeDwDNObW9VmgOQ2fyaU3As+mZX7Ehl4C2t1GLQ7AUWy4G2o02T9qM/ALYJuUvm2abk7zR+eW/6+0/7NId/OUOr862kYtDsA4YFo6h35NdjeTz58N5f868Hzah5+T3dHUK84hd/dhZmZluRrKzMzKcrAwM7OyHCzMzKwsBwszMyvLwcLMzMpysLCtnqT1kqannj5/IWlgDZTpKEnv3cJ17C7pl51c5kxJP0rj50o6Y0vKYFbgYGG9wVsRMS4i3gmsBc6tZKHcE6/VcBTQqWBRXJ6IeCUiTu0ofzkRcWVE3LC5y5vlOVhYb/NnYB9JJ6X+/Z+U9EdJuwFIuljSzyU9DPxc0khJf5b0RBrem/IdJekBSb+RNFvSpZJOl/SYsvct7J3yNUi6XdLjaTgiddJ4LvCv6Yrnb9vL11558juSyvZsGj9T0q8k/UHZOx2+k8v3GUl/lfQYWfcS5Nb95TS+TzoOT6X9LJT/31N5npb09ZS2vaTfpbzPSvpkVT4p26pU85eVWbdKv8yPB/4APASMj4iQdDZZb7L/lrKOBd4XEW+lKqtjIuJtSWOAm8meIgZ4N3AAsJTsnQtXR8Shyl4a9QXgfLL+oy6PiIckjSDrtuIASVcCb0bEd1PZbirOl9a9UXnK7OI4sp6C1wCzJP0QaCF7avgQsl5L7wOebGfZG4FLI+IOSdsCdZKOJetK4lCyp60nS3o/0AC8EhF/l8q+U5lyWR/gYGG9wXaSpqfxP5P1f7UfcKuyTucGkL2HoWBy7ou5P/AjSeOA9cC+uXyPR+oWW9KLwD0p/RngA2n8Q8DYrCsgAHZU1qtvsVL5JlcQKADujYgVqTwzgb2AXYD7I2JxSr+1aB+QNAjYIyLuAIiIt1P6sWT9MhWCyw5kwePPwGWSvk3W7cmfKyib9XIOFtYbvBUR4/IJ6Vf39yJisqSjgItzs1flxv8VWER2FVEHvJ2btyY33pqbbmXD/04d2RVMfjlyQYEK8q0qztyBfHnWs+X/vwL+OyKu2mRG9grUE4BvSro3Ii7Zwm3ZVs5tFtZb7cSGbponlsm3MCJagU+TvbqyM+4hq5ICIF2hAKwke3VtuXxbaipwpKShyrqf/3hxhohYCcyXdEra9jap+u1u4LOFKxxJe0jaVdLuwOqI+H/A/5B1Q259nIOF9VYXA7+Q1ET2ysmO/ASYKOkpYH8q/5Vf8C9AY2ognsmGO7F+C/x9oYG7RL4tkqrJLgYeAR4Gnusg66eBf5H0NPAX4B0RcQ/Z+8YfkfQM2fspBgF/AzyWqvYuAr7ZFWW1rZt7nTUzs7J8ZWFmZmU5WJiZWVkOFmZmVpaDhZmZleVgYWZmZTlYmJlZWQ4WZmZW1v8HANQQ3VaCT28AAAAASUVORK5CYII=\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(torch.arange(0,len(flat_fft)), flat_fft.abs(), '.')\n", + "plt.title('Model Fourier Frequency Representation') \n", + "plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.draw()\n", + "plt.savefig(\"Parameter_Frequency.png\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Normalizing" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(-0.0023)" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.mean(conc)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "conc2 = conc #+ 0.0016" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(-0.0023)" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.mean(conc2)" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "flat_fft2 = fft.rfft(conc)" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x7ff775a99c10>]" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYMAAAEFCAYAAAABjYvXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAABYNklEQVR4nO29e3QU153v+/1VtwQIhBDijZBAGGMQjjHCRtiOH7Gd2Ll2cEwc/JiZ+MTPM8m5kztnZo1PMuGySO4c587kjues43tt7Hg5k2NsYmNj7LGTGL8fgEEEjIQtHgIJ8UY0QiBQq7v2/aNql6p2V3VXv1ut32ctFuru6q5du/bev/17FgkhwDAMwwxttHw3gGEYhsk/LAwYhmEYFgYMwzAMCwOGYRgGLAwYhmEYAMF8N8CLcePGienTp+e7GQzDMIOKpqamk0KI8cl+r2CFwfTp07F169Z8N4NhGGZQQUTtqXyPzUQMwzAMCwOGYRiGhQHDMAwDFgYMwzAMWBgwDMMwYGHAMAzDoIiFQVN7CE++vxdN7aF8N4VhGKbgKdg8g3Roag/hvmc3IRzRURrU8MKDjWiorcx3sxiGYQqWotQMNrV1IRzRoQugP6JjU1tXvpvEMAxT0BSlMGisq0JpUEOAgJKghsa6qnw3iWEYpqApSjNRQ20lXniwEZvautBYV8UmIoZhmAQUpTAADIHAQoBhGMYfRWkmYhiGYZKDhQHDMAzDwoBhGIYpcmHAiWcMwzD+KFoHMieeMQzD+KdoNQNOPGMYhvFP0QoDTjxjGIbxT9GaieIlnjW1hzghjWEYxkZGhAER3QLg3wAEADwrhHjc5ZjvA1gBQADYIYS4NxPnjodb4hn7EhiGYWJJ20xERAEATwK4FcBcAPcQ0VzlmFkA/huAq4UQ9QB+ku55U4V9CQzDMLFkQjO4EsBeIUQbABDRSwCWANhlO+YhAE8KIUIAIIQ4noHzxqWpPYS12zpBAO5cUG3t/qUvoT+isy+BYRjGJBPCYCqAg7bXnQAWKcdcDABE9CkMU9IKIcQf1B8ioocBPAwANTU1KTeoqT2Ee1ZtRDgqAAAvN3XixYcaLbMRF7FjGIZxkisHchDALADXA6gG8BERXSqEOG0/SAixCsAqAFi4cKFI9WSb2rrQHx34ujQHyYWfi9gxDMM4yURo6SEA02yvq8337HQCWC+E6BdC7AewG4ZwyAqNdVUIBMh6zeYghmGY+GRCGGwBMIuIZhBRKYC7AaxXjlkHQysAEY2DYTZqy8C5PZEXRgB+eNV0NNRWcnkKhmEYD9I2EwkhIkT0YwB/hOEPeE4I0UJEKwFsFUKsNz/7JhHtAhAF8PdCiKyF8djNRALAqo8NufP8xgPo69cR0Agrl8zDvYtS90swDMMUExnxGQgh3gLwlvLectvfAsDfmv+yTmVZKYgAYboNdGEIBCEM4RDRBf5x3U4AYIHAMAyDIixH0dQewso3W6Ar7mchABpwI0AXwPLXm9lkxDAMgyIUBjKpTKUkqOHhr9dBcwgEwUlnDMMwKEJhIJPKbGs+CMD3Gqrx2Lfn4Jd3XIoAGe8FNeIoowzBznmGGdwUnTCQSWU3zZ1ovScAzJtSgab2EJoPd0OT6oHdbsSkjKz39Os/teK+ZzexQGCYQUjRCQPJ/pPnHK8/aD2O+57dhBc3d6A/KiAARKNcmygTcL0nhhn8FF0J66b2EJat2ohI1OlBPnbmAsIRHfJdAiejZQqu98Qwg5+iEwavbuuMEQQEYHFdFVqP9aA/YuQZ3LVwmqOAHZM6XO+JYQY/RScMvAoaPb/xAO5fPB0tR87g1nmTOb8gw3C9J4YZ3BSdMJg3pSLmPQHgQr9uZSJvbutCy+Fu1gwYhmFMis6BHOoNe36mC+NfOCrwwuYO3PMMR74wDMMARSgMGuuqEPAZMRqO6Hh1W2d2G8QwDDMIKDph0FBbiYe+Xuf5uSonUn5oAsMwTBFRdMKgqT2EZz52r45NBDxybR1KAwQCUBogLF1QndsGMgzDFCBF50Beu60TUY/tPgngTF8E31s4LebZyAzDMEOZohMG8dwFOoCXtx5EVBcoDWq4s8i0gqb2EMf6DxH4XuePYu37ohMGdy6oxktbOhCNLVwKANZDb/r6dazd1pnWzSykQSHrA4UjOkqDGl54sDHvbRpMFNK9TATf6/xRzH1fdD4DYOChNnGPgaElpBpaWmjF2bg+UOo0tYdwzzOb8C9/bB0U4cZ8r/NHMfd90QmDTW1dMQ+28SISTf15BoU2KGR9oADlr+bSYC1j/eq2Tqtu1WAINy6Eez1UKea+LzozUWVZaVLHp3ozC604W77rAw1m9VndO2Qy3Dgb5if1XgPAk+/vTekcg8k8Vgjke55lk4wIAyK6BcC/AQgAeFYI8bjHcUsBvALgCiHE1kycW6X5cLfvY9OZ9IU4KPJZH8hNUyqEPvHD0gXVeGXrQfRHBUoyGG6cTQEp73U65xjMAjyfFGsdrrSFAREFADwJ4GYAnQC2ENF6IcQu5bhyAH8DYHO654zHyZ6+pI5Px4lcaIMin7u8QtOUkqGhthIvPrw4432XCwGZzjkGswBnMk8mNIMrAewVQrQBABG9BGAJgF3Kcb8A8CsAf5+Bc3oyrnxYUsfvPdaTpZbklnzv8gpRU0qGbAj2XAjIdM4xmAU4k3kyIQymAjhoe90JYJH9ACJaAGCaEOI/iMhTGBDRwwAeBoCamtRKTC9dUI01n3d4Jp6p9EU8YlALFK/dfyHs8gpNU0qGXNj2s9E36Zwj1e+yn8E/g6mvsu5AJiINwP8D4P5ExwohVgFYBQALFy5MyaTfUFuJGeNGYu+Jc4kPBlAxoiSV0wDI/Y2Ot/vnXV7q5MK2n03SOUey321qD+GeVRst/8qLDy8u+EXOjVzM3Xxr68mSCWFwCMA02+tq8z1JOYB5AD4g4wH0kwCsJ6LvZMuJPHZkKeBTGHSc6k3pHPm40fF2//k20wymHZBKIWhVuSSde7V2WyfCptodjoq0EzeTQba7sqwUod5wymMtV3N3sI2rTAiDLQBmEdEMGELgbgD3yg+FEN0AxsnXRPQBgL/LliAAgJ4LEd/H3lI/KaVzbGrrQl+/GZven5sbnWj3ny8zjTq5lt9Wn9ZkzTWDQatKZQFXv9PUHsLabZ14pakTkWhqC6Fa7qXlUDea2kNZv89yjMk5RwACGmHlknlJP7UwV4v0YBhXdtIWBkKICBH9GMAfYYSWPieEaCGilQC2CiHWp3uOZHj8rS/x5VF/TuERQQ2PfXtOSuepLCu1QlN1+M9vSGdXlmj3n6/duX1yhft1LH+9GboQBaEa++mTQteq3HaygLFL9yq46CagV77ZYi2mgPtCmKgtdy6oxstNRpIeAOw81I37nt2U9fssx5hsuwAQ0QWWv96M2ZPKkzp3rhbpfI+rZMmIz0AI8RaAt5T3lnsce30mzunFbz5xL1/txtgkI4/sqPkMfvIbMqGeeu3+82mftE8uIkJUF1Y2bz5V42T6JBtalR9B5KeNqha6dlsnXtl60DLXvNzUiRcfcn5P3f2+3XzEsZgSYjNo/bSlobYSLz7UiJVvtGBHZ3fOTCByjIX7ddhDPnQxUEXA76KbiUXa78ZrMAVVFF0Gcn8SwUFHTp9PWcVV1WU/D1fLpnqaT/uknFxrt3Vi77EefH7AKEehi+QzwlMhUxFWmdSs/AoiP21UtdCTPX1WwUXA/Xvq7vfWeZOx5cAp9Ed0BDTCXQunxWgUyfTXl0fOWH8HAtk3gdgX8J7z/Xj2k/2W9llZVmqZkPyajtJZpAebY9gvRScMkkEXqSedSXVZTjY/5bCzqZ7afzugEQ6nIehS5dVtneizSWMN8Z9JnQlkkTnZp/YdcmNdFYIaoT8qENAobn9neoL7XVj9jIlQbxgaGeNVIyOXpiRAlmZQYi6I9pIUbrvf2ZPK4wo7v+NzU1sXImYBMALwvYbcPBfEvoDfXD/Juha75hTRBX6+bmfSpqNkyNbGK99BGEUnDOSk8UuqSWdSXU7m5mXKhug2aOy785e3HsTqzR2u5oNsodp0ASAYMBbgTA9y++/JInPAQJE5+zmiwrAvJ8o7yURAgL1dfhdWP2OisqwUGhEAYye8dEE1li6otnwG9VMqsGJ9M8JRgQABv7jjUty7qCZm95toN9xQW4nlt9Xj7eYjuHXeZM9j1WvLxdMCpfNb+kjU9mg0cI+jLpu8TI7BRPc2VWd/vrWNohMGyQgCADjV2+94vXpzhzUZklE1cyXV4w2ahtpKvLqt0zIhuC2O6Zw30YIV0/dEaD3ag5VvtmRskKvXf+2s8Y7P7U14+sN9iJqNiuoCT3+4D6v+aqHr76YaEODVrhcebPQt+OMt0k3tIax8swVRXUAjWNdr/85PX9tpaQlRAfw8Baeq/VzhiI4tB055/kaqm5pU54jMbZDXuGbrQWhEjoioG+dMxJ92HbO+Q8r3M73Q3rmg2iGYpFYGIOlzNbWH8MSG3XkPQy06YaABSCaneMa4kdbfqzd34Kev7QQAfLznJAD4CluLZ6pQj0t3UCZSUb0qcKYjrPy0u8XFgR6NDjguMzXI1esfVz4MpQFyLTJ37MwFx3fV1/bre7v5CIy9t6FdJmvecrsvP7rhorQntF3jigrgnV3H8NGeE47wXbUel66LlPo5GfNHsjb3dMb+prYuh48kEhUgGEEKsp2PXDcTH+w+4Wq2zaRZR72O+ikVjs3O0gXVSfup7CGzGuWvNHbRCQNrRvvkhtkTrL/fbj7i+Ozt5iMxwsBtUU1kqpD4GZSJFu1EKurSBdX4/ZYORHQgqBmv0xVCidrd1B7Cy1sPOr5DMByLdsdlJga5m4li6YJq1z5bdkUNdnTudLxWcZuMpQna6Ra/f+j0eQQ0goiKlB2qbvdeXq9sn4DxlD4ZvhvUKGbzQ5Sa4z6bPq10FuTGuiqHjyQYIGhEiEYH2hnPbJvMdXnNP/n+4dPnccH0i/X1x252BJBUH9qFvQbg6ovG4Sc3Xcw+g0yQrJno/1w/oFLfOm+ypREAwK3zJjuOtaurGoCF0ysxa2I5Tig7M68m+LE1uiVvqRmXiVR0TdNAug5NM55dlO7OKFG77Q5FZ0cIzJ5UntFYa6/rd/vdexfVoKPrHP7QchS31E+yBLt9wqu+jkunVmD57fVxzTZ2LXDF7c74fTKvOx5upkgvgS2v96kP9+Ed0wwiACt8tz8qYsabLoAVb7R4mnm8FrxEYysd7TIdQdNQa1SVVX0G8rWf7/sZg173wP6+/XwCQNXI0pjNybwpFdb9BeI/a0Ltl3wJAqAIhUGy9EcHVGo5Mb18BvZUfB3A5wdC+PxACMEAIRggRBVThTp57IOysqzUio+WN98teUtOerljtS8Sduw7l0jUjKyI6tb5gwEz0iiFXavdsVg1shRPbNiN+smjUT6ixOEstceAy8iOVM0lqsMwGUeo/Tee33gA4YiO5zcewM1mtvmypz+zNKeVSy6FphF08762HDljPenM7RyqFrhmS0dMMlQ0jplGNUV2dJ3DY9+eY0Vi2U0fdkE3f9oYvPvlMehiIPtWjg034mmebiZN+1j90Q0XufZlOjWJ0g2ekPfcXpJC3ou12zqtpDov7VcdM/brBWDNHbdNk31eqnSdCzuuq/VoD36+bid0AWzcdxKapsXN9s5UUEkmGPLCAPD/tDOvXUg0KnDPohpMHTPCuqGrN3e4ZuLKm+22A1GTt3QxMNkTmZbk79mjqRxx/nK36ucB0QrSsXjBFjb68Z6TIADDSgacpU9s2I1P9py02qxR/HBO++/bJ8PqzR34+bqdVnRIqlFRbhFC2w+ehrmWI6IDr/25E8I2yyNRgRc2d2DNloOu8erHFS2wNKg5BKGbzdd+faopctXHbaipGomXtx60+s1NYKs7yGljRmBPnPpbbuGmgLtJE0js9FRrEv3DKztQN34UxpcPc82AdiNZP4MdtZSGZs4PNanOj/Zrny9BjQDTGR3UCMGA5jA/Ac6EN2mqk9RPHu0QVPZxG9EB6EZf29vktknMpxCQsDAArAnRerQnrgP5zgXVWLP1ICJKnKJUD+2RRfZBoWbieplt5C5h7bZOnOzpwwe7TyAS8V5kJPbfs6/1Ms5fmnES7VrtuJlSVOy72B/dcBF+ctPF2HLgFML9OjQz+Ucu7l7alirIpleNRNvJc45dWKpOP7cIoeOKE/ngqV7XHV9EF/jHdcZYuHdRjdUf6obg4onleOzWOdZuVa3JpJoe7l883WGKFMLQRBPF7dvNRX/uCHkKgitN06Xq2JQLvCrMjvf0+TIjqte998Q5qzLwmq0HsSaL1UtlH9o3I7oQIBqYF9I3Fe43NlLxfCaO640KyC1XJCpw96Jpjk0dYPT9/Yun4+mP2hyCgACU26oeb2rriglhDmgECGEJ54f+fSve++o4hEe5lnzmGrAwAPDC5g6s3daJ2RPLHe+rDuSG2kqsMW2XMoLDbWe0dlunY1CQskOOZz9tPdqDlzZ3QAcQIOCeRTWon1LhWGTUAaMmnOkwtBUZ5996tMeKUycC/tRyFJVlpa42dNVGKhcwtwWT4BRQdmFGAGZPKk8YoWWfmLqAa+lxv04/dTEO9YYd8QTNh7uxuK4KOzoHIp8a66rwh5aj5iJiHGvXrJa/3gwA1sIa1AglAUIkKqyoldajPdjU1oVb5012mFjcQgbP9EUQoIGYeCLEONm94vZbj/ZYfgM3CMBFE8vxf333Ujz5/l7rvBf6dTz14T4881cLMUEpwTKhfJgvM+KdC6rx4ucd7oIzy9VLpYanIgSgaYTlt9Vb/qFVH7dZNYsA92jAyrJSEBFICGgaEDV/Wgcwb0qF64ZllSIIAGOhrywrdYy/oAbY900PXTMD5SNKUFlWauWCSNRNYr5zDVgYmPRHdEwYPRzAwEKhOpABp33fS3qru6gbL5kQY790S+5pag/hH1/badndo8LYud1pZo7KY9wGjF2jeL/1uNmQgTj/qC5AACIC2NHZbUXZzJ5UHvN76k6xxVZ6wE5tVRkevnZmTB/YbbmqgF2zpcOxYMuFyE3zAIDqMcPx1zfMAuDuiPOKBnrhwUaHZgAAL33egZvmTLQEBAGYNbEcV86osvwhn+w9iZNnB8JKdSEcJohIVODS6grMm1phCQK7sHvu0/344dUzrH5VQwYJzgQ4XQCf7+9yxK17LQCqiUlFAHilqRNLF1RbiVhy8X5n1zGs3tyB+ikV1vslARoIwUxgRnyn5Wjc4IxEjtx0nc+a6SNRieoCod4wVm/uwKqP26w2qkXs7Av2ivXN1m8Jgbghxas3d+B/vLvbNWJLF8L4LSEQNX1Q37hkIN+BAJzpi6B8RAlaDnc7wmMle4714C9/sxm3zpuMUG84r7kGLAxMAhrh0etm4obZE+ImnUlfQFQXVh2U2ZPKHc7O+ikVju9cbwtfVW2fm9u60HK4G3ea4ZHqoNt/4qzDcXfXwmmembKv2KpJAsaAsjs41aG4ZksHvlk/KWYAqppL/eTRDtOGpONUL1a+6YxaUQWJKmB3HTmDnYe6rWip5sPdiOremSGHTl/A8td3QoBcVWs1Gsh+HYdPn3f8li6Ad788hpLggF24sqwUK95o8RRGRMCIkoAlsHQYwvTLI2dw54LqmAV67/Gz+OlrO/HNuRMd7ZpQPgz/+40XG9FVmzsc33l9+2EAxhisn1LhuQCo0W5uRG1BA6OHlziSKp/7pA0dNrOYbJvdjBiJCjyxYXdMVMsfWo56nrPU1JDcnLKpJmKpiDiSqOd8P/71nd0xwkqaRO3n14gckW+6cJpy7FqRXau1Y0SMGZqEfacf0Q2zo9VmAGu2HIQwQ4ADpkZpP/c6895/vOckrp01ztLg85FrwMLARIexoz3XF8HBU73o6Io1VzS1h7D89WZrMEV0gZ++ttOxA3u5qRPXX+zMipUVTZvaQ1YkiyRsOixf3noQP7x6Rsw5x44stUwn4ajA7mM9rpmydsegRJjnlk4xIZwJeTKePmBG02hm/R7V3NPTF3GYW6ZXlVmLirqD6TlvLD7ShGQXsCNKAthgRsSE+3X8/PVm192eeg3GZZnOS1PjUMs+uDlwn/pwn+vvfa+h2rILu/WbHV0HNnx5LGbnKx/s4rVAHztzAUFtIDb+6Jk+rHijBStur49JjJQ9kKgkszSFvLT1IE4rmfOSQEBDz/l+LHt6Y0y4b/f5fufiFRX4r7/fjlvqJ8Fcg6AD+HTvSWw5cMqxaN9SPwlPfeSsCEwY0A4BOJyyUrCUBDXc1TCQiNVnmqzmTxvjW0tYu60zbiLpxrYu13EkACtqb8AUGXucrgt8rboCy66ocbRnzZaOmGMDGuHqmVX4yEMoH1N8MvYM+GVXGpvLz/efwt7jZ2O++5EZlBEwTV/sM8gTMopEIge+/XkHXvH09rfCET0m01X6F3719pfwWnfCUYENXx13vEcAxiiOsNA5pxorBY3qGLTapgPLrjAWv57z/Y4Jvf3gabzTctRSX/ujAq1He2IiTzRyahUTyofh0OnzjgSrpvaQIxYeAK6cPtZyjEsn7Ed7jCxRAAkFgewD1Wn3sunEl6GRy2+rx5otHRgW1DBrYrllalHt4wCsLFF5jW4Cw46AdwAWYcAm/dwnbQ5/x7IravBB63FHiQQZ9WL/uXGjShHq7bf6IqILrHyjxTXXYfXmDjz7yX73nA6T+dUVeObjNtdaTF3nYrOqD3T1xizybkL+sW/PwdEzF6ydLGD0TXuXoR06Mm9tuQ/hiI49x3oc2sg7u45hw65jvkNU1QxrlYmjh0PTzriOJ2mSdCt/bb+OHZ3daD3m1HInKlrt1MoRuP7i8Wg+1O3yKwYXjR+Jpt6w02cIOHxBL30eK2TsbRFCZL3Aoxtazs84iFi3/ZDjtd+szsV1VQjYevaD3SewenMHtpilnb04H3Y+oU0AlhMUMGy8deNHOY6RnzV3nnb9zWCAMM80W8kdviQSFTHqvzR72HdTqgD7/EBowP4pDAFy37ObYpybH+05idWbO9DUHsKT7+8FANy/eDqmjS1DdWVZTFsvGj8S40c5+3hK5QgEA0arA2T4W+RiE47oePrDfVixvhk7Orvx+YEQVm/uwDstR9HUHooRkN+cOzHGRJHI1g0Y2kbA5cDyYQN7qZHDgtDMY4IBwuxJ5TjtMqHrJ492CIOus2GQYsDb0dmNe57ZhKZ2Y7w0tYdw11Of4aev7YwrCABDwKuCgGC0P5moYreInHPhaMxxAsZu/3hPH0qDGgJmhI+dUy5CSGBAu5LjQ16vnab2EN79Mr7TvKw04CoIAoqme/WscbE/YENqnbItj1w3c2DsacCJnj68+HlHjDCQlxsMEO64vDqm/6+YXmmNu1e3dSZMjNXFgIadS1gzADB1zHAcOh1bt2baWOeC5Vdaf7j7hGM7G4nG7ghVAppRfVJth12A6EKgzlZLCTC+s3pzB46ccd89XT97gpUha4ZUW4tCSVCLUf+l09zuN9CFe1a1gLG7lw5WN577pA1tJ84ZJhx4140KaIR5UyscO08AOBQyyjwAMBqvcOzMBYfpQ8DQ6n7z6X6HfVYDcNm0MSmp3pdONRzGqq1/1cdGv6k7a6Ebi9znLsK/7aTT/DhgBnMiI00A4PtPf2ZFvCQirKxEV06vxHWzJ8RohYmI6CImi3n/SfdwVgFjzK+4fSBjfvn6ZkTMiLa68aNco8QA4M/tIat8ikbAL82KqxK3cE313O8pGrVk3pTRjvDQRD4XXRhaZ1Qf8E2t/M48y8T5zq5jrvPgkknlON8fxfxpY/BP/7Er5vNT58JWO/b4qJIsx3BN1cikH+mZDiwMAIwbNcxVGHz3cmeIn19prT52UyPydMJKojpwoT9256Ues0HZJX3Qehzn43zvUKjXcjjbJ1WAgBW3GyF5NVUjY5zmrUd7MHtiOSaOHo66cSM9FxIZ4725rStmIQKcoaLx1rO6qrIYQSCx213VBdZrZ69GbmiBgWc8ALAiS979ynvXKZk3tSImKAAwFo/VLip/SVBzNW0IeBfLc0Nm2foVBCoaGdFSMldENbklQq2zNbasxPPY/oiOUG8YP7rhIjS1h6DBuDcajA2J9BWp2OeKLoB/VJ5F0FhXFROuqSI8VJ4Z40Ziyf/8xBrDqqavQjC0ZWFez9ptnZapNF7fyWs40NXr+vm+k+fQ1B5C69Ee1w2CF2u2dLAwyDX2uHM7aiXOjeZOLVkunjgKPX2RhMd5OaUkAY1iBEbbyXO46ZIJnoJm15Ee1wVTF4a/oak9hFBv2BE94oyi6Mb86tiFULZHxng//eE+tJ9ynwx+UHfMfmn12GkFNILQhSWABjKLOwAySocQIaHKDhjmgZ+5RJUAsQJ8ZGkA//7AIvzq7S9dj58xbqTneFNpOdzt6QvyQ0AjrDazqa+aWZWUIJDYv6P6r9Tjes7348n39xplHWx+qFBvGDcpJaa90AViSnHc9rUpnhsFALhxzkTXzwfe89ffGsEYG7oRTEGAI9EtVYR5TZuSXD+MSLzckRFhQES3APg3AAEAzwohHlc+/1sADwKIADgB4IdCiPZMnDubqJNHDZP0y64jPZ6LViImlQ/DUXNBIAiUDy8BMLC7HFtW4siCdMPLxPP7rQetEFd7yJ8aLrndY/HSdWEJlHQEAZD44TOe3/NYzRfUjEHLoW70KpPZHpnk14YebxEjcu4Z5V8HXKLRAMR1Pqqc6Onz5dPwQmpHEV0k3Gi4QYCjzlY82z0AK0PX3mYpJK6fPcGXMCAgJrwzniAAgLJhmdnTRm3RAv1RgZYk7lUies73+woNlgQ14NHrZmbs/H5I24FMRAEATwK4FcBcAPcQ0VzlsD8DWCiE+BqAVwD83+meNxfMU0wD6dycqA6MCCbf3UdtO8OIbiSx2BlTVorGuqqUFo1IVFg+gT7zQeuAe7KdGwKGKivLeSRDUDMiX9wcs8ngJQya2kMxgiArKBKlNxzFfc9uwtk+d9NddxKOwdO9YUfceq6xX5maVR/vePWwDV8d9+1vmzl+pMOvkyjRDgC2d/g3vSTDLo9ky1RY9XGba7i6F/Pi5Jtki0xEE10JYK8Qok0IEQbwEoAl9gOEEO8LIeSo3gQg+8/JywBWJq/J7zYeSOv3LqRq/I3DOJfwyWQwq1xb2atN7SHMnlQe9zt2ojrwro8dn0pENzSOVDUC6/we30+2lHmq9Lk0oK9fR4mHlCtNYkPQF9HRnsQCkg3kBiEdmX0+HPHlOAWAm+ZMdLyuGpk4gu9g6HzCY1JhVIY0DsAYj08n4cDf3tmNx99yNzVmi0wIg6kA7E826TTf8+IBAG9n4LxZR91xvN3snYXphxQKhsZwXtEM5k2pwNMf7kvJHiy/Lye6zF5Ndqd/Kg8x0YWMgDQfOdEIGD08vknPzuK6KtffySXyGeFuDnS/RKPCM+JHRTV5uuVGqGhZCpDvi+e1ToFk52gih3emyWmeARH9BYCFAP7Z4/OHiWgrEW09ceJELpvmimqS6c/Czj5ZQkrm6Qetx7EhiZ25fWkJBgiLzRo2MvOxsS55R6NbctdQp+dCrDlocsVwHD3jfxfbdvIcxo3Kb9/KBXHdnxNvECaNHoavzxoXoxWd6u3HmQuJAyiA2Ig9P5oBZUkLjBelV4xkQhgcAjDN9rrafM8BEd0E4GcAviOEcA2REEKsEkIsFEIsHD9+vNshOUWth5KJnX26qE34bN/JpJ75bP++EAKrzGxVI97d+NSraqYXwQDnLqq47RsOnb7g6Utwo+Vwt6e5KVfIR4V2+PBdyMWzRMk6i1d7SkWN2Nt64FTC7/T4FDTJElSz53LMMY/coWyRiVm8BcAsIppBRKUA7gaw3n4AEV0O4GkYgsCfvlgAFMDan5BzSSwuKlHdaVvXBfD0h/vQUFuZ1MCIFIDG5Jd8iy2vmHg3CN6x67lC+o8m+Qhz7D4fwcd7TsY47pPx36i+hW4XDUslXb+TF5RnYSCAnPoN0p4bQogIgB8D+COALwH8XgjRQkQrieg75mH/DGAUgJeJaDsRrff4uYJCnbd5HhuelJVkbomT8f6UxE8e7vafSJVv8i22kjFDTx4zImH5iWwj/Ud+NAMvklEce/t1xwI4tix/ZjK3Zyjkmlz6DTLiLhdCvAXgLeW95ba/b8rEeXKNnueJ6AcBo1IlMjRwx5aV4PG3vkwq67UQzGfFiN9aWNnkEzMuPpDGTihZP+y67YesApG94eyYgAYLNWNja3hli3xrzQWNOobzbUP0oi+Djq5ZE8vj1q53I1vRHEOd3SkmKmaSw92GwzuXY9++ALoVxxtK3HF57qLweRongVtMeSHgVhMoVeqnVGD+tDFJfWcQuQwGFfn2FwADPo7jZ3PnzLQvgIPJH5UNXvMRxZUpWBgwDpoPd2NkBpNtmMGNNAEmERCUNvaaYJnc6AxGvvBZxyoT8KxnHOw91oOOAtiRMoWB9diKHJ5zm8tzDYYqmU58iwcLA8bB/pPnYhLbGCaXpFrBlkkPNhMxDs5ciGCcj6xPhskWhZDpPxRhYcA4CEd0VLIwYPJIYcbsFT8sDBgHAsBXR/Mf0sgMYVga5AUWBkwMQzt+g8k3pZy4khe41xmGKSjCuYxjZSxYGDAMU1Cw/zg/sDBgGKagKNCqL0UPCwOGYQqKQVAfsihhYcAwDMOwMEjEk+/vRROnxzMMU+RwOYoE/PMfWxHQCL9YMi/fTWEYhskaLAx8ENUFfvraznw3g2GGDE3tIWxSnofMZBcWBgzDFBxL/7/P8t2EIQf7DBiGicv0x/4j301gckBGhAER3UJErUS0l4gec/l8GBGtMT/fTETTM3FehmEYJjOkLQyIKADgSQC3ApgL4B4imqsc9gCAkBDiIgD/CuBX6Z6XYRiGyRyZ0AyuBLBXCNEmhAgDeAnAEuWYJQB+a/79CoAbiYjzDBmGYQqETAiDqQAO2l53mu+5HiOEiADoBlCVgXMzDMMwGaCgHMhE9DARbSWirSdOnMh3cxiGYYYMmRAGhwBMs72uNt9zPYaIggAqAMQEEQshVgkhFgohFo4fPz4DTWMYhmH8kAlhsAXALCKaQUSlAO4GsF45Zj2AH5h/fw/Ae0IILkfFMAxTIKSddCaEiBDRjwH8EUAAwHNCiBYiWglgqxBiPYDfAPgdEe0FcAqGwGAYhmEKhIxkIAsh3gLwlvLectvfFwDclYlzMQzDMJmnoBzIDMMwTH5gYcAwTFxGlQZyfs5Hr63L+TmHOiwMGIaJS/PKW3J+zse+PQd//63ZOT/vUIaFgU/mV1fkuwkMM6RorOO81FzCwiABY8pKcMf8KVj342vy3RSGGRLIRamhtjKv7Rhq8PMMErB9+Tfz3QSGGVIIrlqWF1gzYBimoOB01PzAwoBhGIZhYcAwDMOwMGAYpsAI8qqUF7jbmRjK8pBkxDCS0SNK8t2EIQkLA8ZBUAOGl/CwYPLHvCmc05MPeNYzDiI6T0Ymv3AwUX5gYcDEcLj7Qr6bwAxh6iePzncThiQsDJgYzocj+W4CYzIU86/K2WeQF1gYMA40AFPHjMh3MxiTfJtMpPsol0KJaxLlBxYGjIOSEg2zJpbnuxlMgRDVjf+1oaiiDDFYGDAOgkS4c0F1vpvBFAhSM8lliYhNbV3W3yyEcgcLgzgMCzhH4lAYl8NKOMegUCiE8SZlAOWwMXYzkZ5vO9kQIi1hQERjiegdItpj/h9Tc5aI5hPRRiJqIaIviGhZOufMJYGAs3uGwrisqRyBV7d15rsZjEm+BUKpuSGqGzcyZ+d8p+Wo9Xe+r38oka5m8BiAd4UQswC8a75W6QXwV0KIegC3AHiCiMaked6cUFnmjGoIFODIzHSbjp65MCSE3mBAABie59oMcpd+vj+a8m8kO0b/YBMGI4exppor0h1pSwD81vz7twDuUA8QQuwWQuwx/z4M4DiA8WmeNyeUKSaTEQVoQolmeOWuLCvlpLMCYURQw9jyYXltw+HT5wEA3ef7U/6N4UnOm1vqJ6X8XSZ10hUGE4UQR8y/jwKYGO9gIroSQCmAfWmeNyccNCeCRM9TOxIxeXRqC0bA5e4vqK1E8+HuNFvEuBHUKCmzR78uMLVieNba4wcpBKaNLUv5N0YkUetq/KhSPPbtOdbrfGtG+aY8h5pRwp4mog1E1Ozyb4n9OCGEQByzOhFNBvA7AP9JCOG6rhLRw0S0lYi2njhxIslLyTzTlHj7QhyWAQJ6Iymq8C53684F1WynTQIvE4jb21fNrMLEJAR3iUZ5N9nJ81dXpi4MLq+pxKzx/nwOJ86G0dQesl5PGeI5Lz19qZvnkiXh+iaEuEkIMc/l3+sAjpmLvFzsj7v9BhGNBvAfAH4mhNgU51yrhBALhRALx4/PvyVpkjIQSwuwgNuo4UGcu5DagFFNTGNGBNFQW5l0aGkh+lJyhVfIpdvbH+05icqyUt+/PbxUwxFFO801cmeeqlAKEPDodTPR0+c/q90eWppvYTiUSHd1Ww/gB+bfPwDwunoAEZUCeA3AvwshXknzfDlFrZHy/YZpeWqJNwSCyNCUOXMhgqb2EBpqKzFnkv/Es/Gj8mvXzifJ9nyoN+z72L5+HWeTWESzQflwI4iiO4l2A0YoKsGIyGs92oNjZ/p8fU8jZ2hpqDd1X0WhUXhbSSfptu9xADcT0R4AN5mvQUQLiehZ85jvA7gWwP1EtN38Nz/N8+aEM3meiH7QCBgezIxdURfGrqypPYSvjvb4/t7Jc2EMG6K23dFlQdf3vbSlZEotaETQshDgP2dSOS6r9hckUGre11PnkhMGQhiCsj+iY82WDt9C88Y5E9FQOxChPiOHIa3ZJpUtWy617rRmsBCiSwhxoxBilmlOOmW+v1UI8aD59/8SQpQIIebb/m3PQNuzzp9ttksA+P3WgzlvQ6IMzO8vnIb6KZmp8kgwFqtNbV0xAzdeM3QhsGjG2Iy0YbDxD9+ag3/67qUx98ltDb9j/hQrOscPOoCaNBy3XiyorcTy2+t9HSsX4xnjR6V0LgEgHPEfenHD7AlxXw9mSlJY2UvcojyyxNDczvlEVekDeciNjxdnTQBurp+EBTUxuX4pUVVeiobayhi7NiF+BmrVyNJBFQJov42pbrwvmjAK//TdS3HvohrMnlQeIyx1Zf27dtY4PHH35eg41ev7HCNLAzh6JvPlxOunVPhOLNxibogevW5myufrj/oXBmok2wetrm5IB7malhoBUytTd2iPTcJfJLmQhCBNFxYGcVBV+myqrKVBzdVOP3Occ0dmP0YAWLutExttDrd0OGVGcoR6w44JtnB6JUqDGgJkDJhSZYfzf9w8G5v3u7eh0HzLk8qHWUJdI+CK2tQE6cjSAO5dVIOm9hDueWZTwnyPfSfPAUjOTHR5TSXGjkx+AYmHBmOTc6LHnw1fljNvqK1M2WRRl4RWoZ7imA9hmK2SFRoN7OYDGuGXd1yK6y9OPbDlmM8+tzNozETFjlq986IsVfO8aMIovPhQI65zGWj7Tpx1vC4f7rRRE5Cyvd5tnG1q60JjXRWCNmnw54Onsfy2evztN2fjl9+9FH9z08W4Y/4UTK8qw6PX1uHeRTU4c97dvzIpxRyIdPHS4o6f7UO/uXLrAhhTVprSA9jbu3rR1B7Cq9s6Xc0gQjm9XFSTqQh7/ewJOJfh0MLSEg2NdVW+7dfXzhoYk5VJCKbasWX4+qxx+KfvXopHrpvp2cd24RzQYosk5tNnUDduJB64egamV5XhoWtmYPakcuw+5t+XZkej1HwGuazNxMIgDuoubmmWqnmONJNynvqoLeYzUuwYfREdpUENBEObuHNBdcolpwMBciSeBQPGQtFQW4nrbbbaSFSg+XA3GuuqsPLNFvzLH1uxbvthHOjqxXOfHcDjb33pOtDvmD8Fl1aPSalt6VAa1HD71ybDLRJYnVwCwMollyad3HP6fD/uXrXRc4ddoggjmdXtN7SUYOzgj3RnLrS0esxwLL+tHg21lZjgM7PZPraSqU90zaxx+N0Di3Dvoho01FZizSNX4ea5E3HR+JEOrfNoTx+i5k2J6gKtSuBCV5KO60xy9kIET33UhgNdvXjqozbcvWojthwIJfxeQHOarr45dyIWpqiB5tIyzcLAg1yaNxbXVWGthw333itrHK+XXVGDFx9qxN99azZefKgx6bwAsv1fP3m0FSdPAL7XUG1FcoxXFguCoTWEI7pj4Q9HdKzbfsj1XPl4LsKV0yvxw6umY932w+j3YW7t7g1j+evNKSX39Ee9g3qDiuNv15EzAPyHlgY0QmNdFSoy+NSvztMXsOKNFqze7C+6Rw3zTIQMJ5WbFDsNtZV49LqZ+O6C6rhmo+c+cW6Ibp03OeF5Rw93j+hKl7PKE//6fdZ+uXiC04f0we7UE2iHJ5G9nS4sDDwQcCa/wOV1pigfUeIqfOZXV+Cxb8/Bo9fWOUwyDbWV+NENF1kLd0NtJeZOTrzwzq+uwLASw/Y/rETDsitqLF/AsBLNofncuaA6RgNprKuyQg3teO129xzr8eUAzCT/cOsctJgLrxclAaMsRDBAaOo4jUiKunhJgDChfJjr7k219Z48G8bqzR2xznkynMsqD14zAw21lb61UVUT8SIc0fHz15vx4uaOmM+mVo5wXItqajuVIOZ/yWVTcM2scVhxe70jPBQAmtpDuO/ZTfj1n1px4ORZj18ALigF8e5dVIOLJsT3OSSTyAcAZT6TR8cogjjgs5zIl0d7HD6kcETHoRSTByOZLj4Wh6ITBpm8IHWQNdZVZUVjaKyrMspAKD9ePqIETe0hPL/xADpO9eL5jQccqfp2EpULuGjCKPz89nosv60eV100Dstvq8e9i2ocr+0TuKG2Eitur3dM7obaSiy/rT7GD7CgthJXTo9Vg9dtP+y5m/Lbj6OHB11/24u12zoTPlD9+tkTcM2scfjG7AnQUxQE1WOG46WHF1tC0w9vNx+JiZYRAvj8wCl8c+5AWS+NBp4D7Pd5wBOSqGEU1d01mnuvrME9V9ZY90bXhWMD1J8gsuXNL47g070nsfLNlphxKrVKXRiRVl495lZ+Yl6C0OmoGrqVgD6fC+zZ8IBgIgDLrpiGm+bGLb/myZHu1KLCcmmhyI5+lUcyGYilqvQNtZWYOHoYjvrMpvTDnEnl1iK85LIpWLf9sPVZ1chSPLFhtzWJ+iM6NrV1ue663kuwA993/CzuWbURIEIkqmPLgVMAgJVvtqCvX8fGfcakv3dRjfWbK99sQTgycGzz4W680tRpLQoEoMRmErjrqc9cbfJ2Ahpw9xXGOV5w2Z2qNNZVoaw0ACCxrRYAXmnqjBvxEQwQPmg9jkhUIBAglAQ1RCI6NI3w4DUz8MYXh3HodOzE1WggkaokQPi3exZY9+GFBxvx1If78M6uY9bxcyaPxueKfbl+8mhs64i9jr5+w/QW1AhRXUAjsjYifs00UyqG41Ao8e4zQEZWcCSix8yVyrJSNNZV4WXzHgdMH5IkkYlLCpmwyziVWmV/RAcRQTc7U4PRp3KcbO/strLgAWD15g7HnHDDT/ilXFQ1guWjSMTXplbg8wOnjL4wtQK/vpYYUtzgB3PoNCg6YZAp3OylTe2hjAoCAJhtCxVVbexvfnHEmmCEATuyyqvbOhOqkwJAOCqs4hX9ER1vNx+xFqKILrD89WbMNoWTfScX7tex/PVmx45SA3D1rHH4yU0Xo6G2Eqs3d7hGPmgU67S9c0F1jKPQiz/ZFlg3aseWoeNUr9Wu/ojuGY44flQpLq+ptH4zEhX45twJGFc+zFos7IIgoAENNZXoi+ioGFGCj/ecBGDsmFuP9jjMdM/81UKs3tyBt5uPWHZuVRiUjyhBn1vkEYB3vzxm9VNEF1ixfuBezJ1cjl1HvPtLI+DiieVoag8ljD4JBDSsuL0eod4wdhw8bfWFDDltPdqDqMwLUAovxdOA5ldXYHunofXoIlarllrl281HUD95NJ77dD/6owLBAOH62RPwzq5jEACiUacgebv5iHqqWBKsl0HNCBII9YbRc77fNVDDjUV1Vfibmy7GUx/uw3tfHceLn3cgqBlBF16pE6OHBzF/2hh8ZI4Vqw1BDfOrK2LGRCL6ksjRSJeiMxNlCs1FIqfjMyACHr22DmOUB+as234YP3ttJ5raQzETyL74CvkjLiSz6SgxfQQlQQ23zpvssAvrYsAsIHdyATL6QhdO00IwqFmCAACe+3S/e9uUxkV14OkP9yHUG86ICjxx9DBHuwQMh3zQJUDbLTJFwBCmL37egaeVRWLS6OHY1nEaOzq78dGek9Z5ogJY/npzjCnk3kU1VgTN+4qmJjcXy65wBgRI1EU8HBVYu60Tqzd3xBUE8rvlw4IoDWrWhCa4r5ERszzE4dPncf3sCRhu+pBKSzRUlpXi5+t2ImpqQBHFTCQ8qvIRgC86neYv9fqlpvnp3pN47tP9iJrjSYdhtpO+rJKgUxtxcyCPLRvwsZUECMM9snQJwNdnjcOaR67CvYtq8KMbLkpYMK8kQAgQMNwMwW092oN3vzyGqC6MjVFUoHqMt0n2G5dMwKf7YteJ7zVUpxSansvQ0qLTDIiSf3i3Rkb0R78tUkaPihhVN1lHlZ0ll01B+YgSXH/x+Bi194XNHXh560HctXAaCAOLe8A0G1iLUNTdTLR0QTVW+zC5zJlUjl9+91Irl0D+zvLXm6ELgVLbRGyorcQLDzZiU1sXKstKsWJ9M8I27UNXO9mj0wMaxThot7aHrAVAaiap4lYz50xfxKzp4/xlIYBx5cNQGiD0R4XlAJYakMqR7guek1EKTvu9aGoPWX27X8kPGTuy1PK7/K9NBxIu8ICxmPnaGQPY2NbluF+h3jAqy0rxj+t2WtdAMBbfHZ3d2NHZjdLggJbQaEa02RVMogFNtKk9hK5z7g5kt9r16vW/uq3Tutf2cSTDlmXb7eMSMARsR9c5PP1Rm3WOUG8/NDLqGD1y3Uw8/eE+dLqY9koC5NiwNLWH8HKckjIagLsWTsPUMSOs6zbmhvO49jhZ5K9vPxzTFxoZocWzJ5Xj91s6kExS8Ygc1vwqOmGQyspSN34Ufnj1DLzfetyy++qIXfz9hwUCv1hyKV77cycOnupFY10V/tByFOt3HPYsPBaOCuw+1uNo/m1fm4yyYUG80tSJaFSP2TVJGkwHbiIVdIG5GAEDWo4sp+A2EeXi1dQeiunWSFRg5RstWG46l394TR1++trOmHPe9rXJaD7Ujb0nzlnvnToXxso3W7D8tnpLdfey1Seibvwo7O86Z6ntMgIq4qJeBwKEpQuqsXRBtXW9rUd7oBFBiFinarxdWalyL2S0TNjMA5lR5YzJP3XOyO5uPdrjEAQEYI6LGUhGcLUe7bHMU/E4eS6MV7d1on5KhbW4v9Ny1HENMyeMwr7jZx0mtebD3ZhqOm3VkXnjJRNixotfxo4sxZPv77X66OWtBwdMjIrpkDAw1ty4uX4SnvvsgJXcJ2BoZ+99dRyPXDcTj1w309WcKAC0Hu2x7vWmtq644aGlZkSdbMeT7+/17V+wn1NFF4Zv7oUHG7Hmkavwj6/txJc+zaSTcvhwo6ITBqnsMvceP4sVb7TgroZqa6BqFLv4G5m5SCjZZaLYjoOn0R8VeGPHYeim6h2zo7YRjugOzeDNL45gzSOLHYuX14T5h1vnYNnTn7m2ze7oVRetFx5sjDsRAWNX5zaJdnR2475nN+GFBxstx/Mv3mzBeVuA//6T5/Cr710W07b+iI5Qbxg/uuEiNLWH8Mwn7mYmwHD6Sp9IMEAQwjChlZj25ve+Mu3eBKy4vR6zJ5VjrW0nKpFdbxdyK99sMZ228v54NsM4B4BLqyuw7IoaR5/ZfSz9Zt/aEcI4Rl1Uv1ZdgeW31+OeZzZZi93YkaX4vpnzIc+xZksHzoWjjsXczqHQecshr5HheOxXLmZkaQAlAbJ25oEAYc2WDkT1Abu6dPKWBDU8YqtH1FhXBQ3eARpXTK/Eto7TVl9u7+zG1vYQSoPGAiu1Q4Kxo/9w9wnrPPVTKizB4TYON7V1uQr3qGnGaqyrQoBin8/RHxX4uakZlQQIP7x6huf6cJl5H1Sn97ASDWFzPNtbcMf8Keg6F0b95NEOrQVw95PJ4I/GuqqksphvmpNa9FIqsM/AJBzRcaKnz7KTqzs/wFhEpo9zj3kuDQ7sqyJRgec+aUPYTEqSNthELK6rcrXhq3kFbtizPO0QjAVHhoeqi5afHV+8tof7dYeW8fVZzkieiaOHW227d9FAXkNJ0LBRP/n+Xjz94T7PHRjBqMx676Ia3LeoBiu/Mw8BGrCJf9B63BIyujAinqSJS32qWFSxgatJdDfOmRg3eqN8eBCBAGHnoe6Y8Em7j6UkqGGxMnaCAcPkotrApVBZcXu9NRlPnQvjqY/aLNPfvYtq8PqPr8Gvln4tJvbfrbW6MBPilC6dMW4kXnx4MW6eOxGXVVdg1vhRlkYV0Q07v5rQKGmorcTD19Y5fi+gmUlmAcJ3L6+G/blskejAGBOA5c8IaISZ40biuovH42vVFfjhVdOx8s0W/PpPrbjv2U2uodOyb9VrlQEVm9q6XGtDaTQw98JRgY1tXVYehQzIkHk0qiCQ1/zCg434r9+ajZf/81X4p+9eapXYeOLuy/G7BxahpmqkY34QgLuvrMG9i2rwzbkTHWMiXlu98BtanAmKTjMote18kmVc+TBP26WkbtxI7D0emzRTVhJAODLgnEr2AeIytnzlknnWbiboET3kRUNtJeZPG+MIcRQwnHutx1owe1K5I8TPy+yksnRBNV7ZehD9UYGABiyoGTBJqea062dPcKjssqyF3OVKLaeyrNQKXY0nbQIaxajuEdOPEtEF2k6ecxx/0iwP0VBbiZqxZY7oLzVCTO2LR6+biRtmT7CcqCpnL0QcJha7z8DuY5H2dzvXz57g2OnLqCOpUYV6wzG77rebj1ify3OsXDLP4QcAELMrtmsGdoEgHegf7zlhCEHlGo+fuRBXS5TJkQLGLnLZFTWWfX3ttk6HUA5ohAAESkzNYN6UCisizR7N03z4DIQQcUOnZSSS/b5oBKxcMs86VvUQVY8ZjrlTKhxj8VxfBMGAZplcpZkynsZt74+G2krH/QAMjc2OgOEfsIdoq+uJ3zUq2QzwdCk6YZCKGCAYaqRcdOLtwB+5biY22MIAJb1K7YNSpaRzwAxULwlquHL6WHxxqNsRx2xfmAMBDXpEt6KH3AaUFz0uQkhgYKL96IaLEgo8lYbaSrz48GKH7XWrGcaomtNkxVMvU5vs3yff3+vLefzgNTMAwDIjVJaVWn2vCyOyxM44Wxz4GMXns1C5t+oCDhgLsFeb5PvS7BZvoqq7WHt8+r2LamIWFTcTpKpFyIqyD3+9Ds9+st9y+i+/rR7Nh7uNEiOKz8C+8I4oCViF9XQR20avSCd7G60ADYJDSD/94T7HsTdeMgGXTRtjjbFNbV2uyW5RXSCoGc/ri9enod5wjHPbHpatBo5UjRqG62dPwAe7T1jmt7aT5xDUCHdfWYM7bW1PBTkn3YpErnyzxQoLVtcTOZfWbuvEGzsOo+eCd3RTsoEw6VJ0wiCapFYwqXwY/vKq6UktjL+841L87LWdMTV6JMEAOWLdNQIeumYGykeUOHbEnx84FbM7efL9vYhEdSvmeu22TmsC2238bjz+1pcx4ZF2IWSPFEp2Iqjf8dIu/GoelWWlCQUBwYgMsvs41PIMFcqCLwvCAU7BALhXnbX7D+57dpMloKwdsLnL1jFQGkDTKCZjW5aylte94vZ6Rz8kqh8lTWlPfbgPx89cwLIrnAJD9fWsXDIv4a4WAJ75ZL9lgtvw5TEENXLsju9fPB0tR844tBQvfrfxgEMQ/27jAavv7GVHSgKER66bGROJ53a/1Ygmr2txC7t+YsNu/OSmi42HMSk/vvOQoQ2vuN3Ibfh070nopq9pypgRKQkCKQDsczioUYyPwG5+jReY8ef2UFxHsjC/n47QSoaiEwbJpmgc7enzLQgkctL83FR77YwaFsBVM8dhw5cD6qkugOc3HrB2oVYyl82JKlEXUwJ8ZSCrGbCAsYj5XTSSQd1Rx9tte51T5hnEEwgChtnH3l+q8607jiZiFwxur+3Y/Qcyoe7WeZOtHfeeYz0D0VpCxGg89lLW4YiOlsPdePGh5DQwAJhv2027tU+OA3XcuPHqtk7H+JSL4bIrB8InkxkTasG1DV8ew5Pv78Xh0+cdDuK7Fk6L+V31fl9WXYF5Uyt879Ddxsune09ii7mhko5xqe3Y++knN12MLbZM4sOnz1u+CXsobrz+sAtjwoBZLhIVjvQfzeYPcwvUsGv5fh76k044e7IUnTBItMC48dSH+/DMXy1M6jtSIPz3t3eh58JADZOzfVG891WsGUku5KqZo+d8vyOSws10sXZbp+dOWw7SCy4lOr9xyQRLXc008bQLt89UU5dfzcAe4aOL2Aeky5Lebv2TyGRlRxXCP7npYgAD5TrsbVXLNACxY0549IMXXlFeXu3zY0tW2yTNW0sTLMBeZsnpY8uwvbfben0uHMWv/9Qao224FddT77eq+cSjqT2EQ6fPW6VDYJqE5ILffLjbNKkaC3NAI+j6gDYs59TabZ14pclIMHx560GAyHJwa2bQiJfmbRfGjj7VyErG0wBcfdE4S1txC9SQ9zioka/SFn7D2TNBWsKAiMYCWANgOoADAL4vhIgNBzCOHQ1gF4B1Qogfp3PeeGhxUsW9OJ7CowWb2kMxiVgS9fx2G/Omti5rkSPAYfu1h3naB2S8nbYcdG5s+PIYPtpzIq5pKZN4LSJN7SHcs2qjlej14sOLHTs9gjGX3QKKJpilIuSOfYbiwF92hXeeRDILqJtG8+T7e2NKdhOcpb4ldie79D8lg9viIc8h+9WPw9OOqgndPHdijPlGJZ5QUiNbZK0mP9pGi61AnwYj6iteOKlbe4Ia4Z5FNaifUoGVb7Y4tGdZL0sXAOkixi8g/RYyysmYt06tyUvzBgbGkn1jQDA2XB/vOeHYRFiOYmXsOawCUeGaKKcymDSDxwC8K4R4nIgeM1//g8exvwDwUZrnS8jI0iDOxHHKuKGGAfrBLYFFLmrSxhw1o2+WXeEcmMNKnAW7Eg3EeDtMOUjdNINEv5tJ7Db3gGmekju/tds6LaEpyywsXVBt9YOM7Gg+3I2XPh+ocSRgRIDYj5MRP2o0jle/JeMsV/tZ9m243yjqJnePbgu96mT309924ekluBJpDPGw7yoJwGXTxiT8bjyhdOu8yY4EuJIAIRoVICJHBI3bddozf7UA4ZWmTkSiia9pU1vXQP2sqGHvVxMlAWDNloOWqUoXcH3WtHyCn30DZ/cN2cOdvcyfUruQWtCj183Eo9fNjLnvXmNPFSiJGDSaAYAlAK43//4tgA/gIgyIqAHARAB/AJCcPSZJvnHJhIRVDlVSieVtrKtyJPAAclAZyS3PfXYAUQhomhazQ7EX7Hp+44GkVH8VOege+O0WnFZMKHKA5yI8zTFplaJ3atQKwXuyvPflMUc46PaDp2OOcwvx8yIVZ7n9u2qJB79hiIlwW+Td+iPe4pwI+65SwN8uM542JUtD/KHlKG6pn4SaqpFWKRN7BI3KprYuh0+hfvJo7DzU7eua7OYlexiz2tcrl8xzFFOU/gS7oGmorcRdC6dZD/ex+4Zk+Q7pGHYTUvKcSxdUY+22zoS1tdwiiewCxUujV68/V6QrDCYKIWTxlKMwFnwHRKQB+DWAvwBwU5rnS0jZsOQvacfB046yuX6QO8GVb7Rgh61Il64LtBw544gIUlV+e2noZFV/r7aoNY9mjR+JSWNG4NZ5k3NiImo0E+YGdmcDCXN3Lqi2yiLbI2vcFs875k91hEPeUj8p5rhkQm3TJR1hEg+3Rd4tsTAVX4EkGZ+JJJ42JZ+tEY7oeH7jASxdUO1Ls7VrWJpGWFxXhdZjPb6uye81zJ5Uju9fMQ0th7rjCpo7zYXczawjzYJ+hJQMGJC+Bz9ajuxfKVD+8jeb0BuOLxAKSjMgog0AJrl89DP7CyGEICI37eevAbwlhOhUn+frcq6HATwMADU1/nZ+KntTeGD1n3albluvn1phLv7GpctqoFtc8geA1KJC/DBrYrnDeb6/qxf7Tp7DlgOnsuJEVhfkhtpKa3fmVvTOK7JG/Z2b6ydZ4ZABjXBz/aSY86ZqNkn3GjMphNwWebffT9bUlegcfvASgOrYFfAOMVZ/b/lt9dbYeH7jAd+bID/XYPdJBTQ4nNluVQTU/rSHjPq5Hkc/mL4HgeQ0NxlE0Rv29hsQCizpTAjhuZsnomNENFkIcYSIJgNwe8LKYgBfJ6K/BjAKQCkRnRVCPOZyrlUAVgHAwoULU0q5cKti6YdkbmRTe8hS9SJRw7H1zbkTMb58mGUSkvVxVPGXzk4vHrKOivRFWA8a6c+8z8BrQfZT9C7R7xgx49JpEFsZNB2zSTKs3tzhEGzLb6uPa0JIFnVRAuAp5FLVTuwmyUxoiOrYVYv+xfv9UG/YoUX43QT5EYZ2n1REB26+ZLxniK78Tbumbu93P0LK3g8BjQCiuIUkvaifUhG3OGOOc87SNhOtB/ADAI+b/7+uHiCEuE/+TUT3A1joJggyxdiRpcCJc4kPtJGMbV1NTgKMaIrLpo2JGdxSlVy7rdMRKSTtholsjslgnzT2B3i4VV91u6Zkdp7xFuRkFi6330kkLBvrqqxy424hnpmgqT2E5a83WyavcMR4EFCmhZC9r5IxUSRzHSvWN6M/KrC5rSttDdFrYfbzm+lsghKNKXUeTSgf5lvbTkVTdxPkqWhuaukWr/blwswLpC8MHgfweyJ6AEA7gO8DABEtBPCoEOLBNH8/adQSBImQj2H0m/yiFjczfiO2hlCiHayboEgXOWmefH+vb1txKmaXTGk3br+jOm1lfLajTTbNIRvI0gkSjSiu6S8TZENjVKO47CXHUyUdLSVVc1civHxSfsiUKS2V60nkDxhUtYmEEF0AbnR5fyuAGEEghHgewPPpnDMRagmCRAiBpNLT1XBDAK5PIIs3yLJp6mhqD2H7wdMgImhw2u7dSKUtmZrYiXaabkJKRqbI+PZs7JykyU06PGWYrJcJLBMk26d+tDl1VNpLjudqt2knU854N39VKtnesk3ZElKJaKyrci13LfnOZVNy2p6iy0BeuqAaaz7v8F0mVqPkK4O+8GAjntiwG5+Yj0KMuDyBLN4giyco0nFSSkeaVa/epYaOSqadjMni11kp+zdbPhe1TV5CKlOT0/68ZHuuhF+flR9tTu6Y7SGMuco7yRbxnseRzqYk3nezGb1mz3uoLAvidO9AZdy3mo/iL5OMckyrLTk5Sw5pqK3EQ1+v8/3Q6wevmZF0ZzfUVjoScHThbpf3GmRei026kTJqIpyux9bQ8duWdHBb6BJhn3AAcOj0edeokGzsoN3I5MKvsnpzh/VUODmG/PYT4F+bkztmNVEql6aHTJOrAAJJNqPX7PkXAQLmTR2DT2xJfbkW3EUnDADgzS/8J50lekC2F8229HrAqGuejIPObbFJd6CriXB+J36md7zJLnRqyQEZt+1VbjjTO+hcoz7XWH1uQSKSLbPRUFvpO+qn0MmFZmgnm8JHvZZb503G5raupOdvpig6YdDUHvJV80OSqgtSPkRFkgl7bLoDvaF2oFY6AWnXbE+FVBY6r7jtSFS4lhXwi596P/lYHNWyDupzCxKRijaXTU0nl2RKk/V7/7MpfNyuxR6Snuv5W3TCQEaf+CGgIemCYhI3R3W6Mf2ZGOj5nvSpLHRucduRiOGgdysr4BeviZxvjUEKx2RNaRK7Ga4YFvhkSXeMx6uj5XaubDqY7dciBVSiqrLZouiEQWOd+8Ox3dASZETHw602vp+Y/kTkezFPl1QWOnXCAcATG3ZbDyRJVT33msh+Vf9sag9uTzvzQ7r+hmIlmXsVr46WG9mckzKB9WRPHz7YfcJ3WYtsUHTCoKG2EjfOmZgwmQMwzBCp7uTfb41NtibktpaISj5NH3ZSWejUCWd/IEk66rnbRPZb4qAY/Q3FiNe98poP8epo5brdy57+zPGoUyB/EV9FJwzUR/DFQ9Mo5Z282zMQ/FaGzAaFunilw50LqrNiO/Wj+uc6asUv6fobihG3ewXEL+/hVUcrl6zd1hkjCAi5dxxLik4YqOGVBGDO5HLsOuIsYGc8QDt+6d14LLuiBjs6dzre05A/zcA+IcL9uvV82EJYwJJFFWzJZJT6JZHqn+uoFb+k62/IJ9nSXN3uVSJhnu0kQj+oRmqNgHtcoudyRdEJA5nVJ+WBAGIEgfxAR+q7Plnbfd32QzhxNhzz0Plco2ZGp+N4zSdN7SE8sWF33nfl2XYcpkOq/oZMkOqCnk3N1eteFaIwt2NPCgxohF/EcWTngqITBn59BvanG6UyUOy13TUySlkvu6Imb4uGnBCZcLzmA3slWPtzafM5kQe7Mz/TpLOgZ9vspt6rRMK8EMyqMimwUDYcRScMAOCR62bi3a+OO4qNqRAGHl6dyk2wD25dAF90dqP1WGomp0zRUFuZMcdrLnGrBGt/uHi+JwljkM6Cng+zWzxhXig+oULacBSlMGiorcQvlMfgqQQ0SitOu7Ks1FFgSn24Rb4iewrZvOGFWgmWAJSWaCwICox0y1AX0rj0ey2FEqGXC0hkqQxwuixcuFBs3bo1rd+Q9md79AVgOI8JSEs9fPL9vfiXP7Y6FrBhJcbvAd6RDEwsUjOQSWd3LZyWMSfaUJrMuaCY+jPRteTKlJTpPiWiJiFE0s+aL0rNABjo4FvnTcbGfSedIVxpOo+BgTpA8lF7y2zPRMjGg0qKmWztGgvBLlxsFJJZI10SXUsuTEmFNEaLUhioHfyNS5wOZU2jzET/EAEQ0DTNsZMt1LDEQiYbi0yh2IWZwUku5nEhjdGiFAZqB48rH4ZSWzVPIudOPtVzRKKGnTuqPM+g0OyjQxUWykw65GIeF9IYLUphoHbwUjOT9YXNHQAAPSqSerqZn3OoN7GY1OnBCgtlJl2yPY8LaYwWpTAAYksZtB4dSDzTAew4eBpNaTxFqJBuIuMNC2Wm0CmUMZqWMCCisQDWAJgO4ACA7wshQi7H1QB4FsA0GFGY3xZCHEjn3F54lTII9YYdzxt9Z9cxfLTnRFoOm0K5iZJiivRgGCa3aGl+/zEA7wohZgF413ztxr8D+GchxBwAVwLwV0kuBbyKVkmzjqwHYs8LKAakEPz1n1px37Ob0NQeI5MZhmE8SVcYLAHwW/Pv3wK4Qz2AiOYCCAoh3gEAIcRZIUTqj69KgFz0A0opA2nWuWdRjevngx0vIcgwDOOHdH0GE4UQssD6UQATXY65GMBpInoVwAwAGwA8JoSIpnluV+y2/MqyUmtRlCadhtrieR6snUKKSmAYZvCRUBgQ0QYAk1w++pn9hRBCEJFbOnMQwNcBXA6gA4aP4X4Av3E518MAHgaAmprUq/fJBT5ePfNiEQKSYnJos++DYXJPQmEghLjJ6zMiOkZEk4UQR4hoMtx9AZ0Atgsh2szvrAPQCBdhIIRYBWAVYJSj8HUFHhRTfX+/FIOQK6SMTIYZSqTrM1gP4Afm3z8A8LrLMVsAjCGi8ebrbwDYleZ5EyLNJhpg1fdnx2rhw74PhskP6QqDxwHcTER7ANxkvgYRLSSiZwHA9A38HYB3iWgnjJpuz6R53oRIs8nVs8ZZIaW8uBQ+XgEADMNkl6KuWgoYZod7Vm1Ef1SgJEB48eHFbHYocNhnwDCpw1VL42EWlDP+ZwqdYvB9MMxgI10zUcHjVlCOYRiGcVL0woBt0AzDMIkpejNRMcXfMwzDZIuiFwYA26AZhmESUfRmImZw0dQewpPv7+V8EIbJMUNCM2AGB5x9zDD5Y8hoBrzjLHw4+5hh8seQ0Ax4xzk44MqrDJM/hoQwcNtxsjAoPDjyi2Hyx5AQBrzjHDxw5BfD5IchIQx4x8kwDBOfISEMAN5xMgzDxGPIRBMxDMMw3rAwYBiGYVgYMAzDMCwMGIZhGLAwYBiGYcDCgGEYhkEBPwOZiE4AaE/jJ8YBOJmh5uQKbnNu4DbnBm5zblDbXCuEGJ/sjxSsMEgXItqaykOh8wm3OTdwm3MDtzk3ZKrNbCZiGIZhWBgwDMMwxS0MVuW7ASnAbc4N3ObcwG3ODRlpc9H6DBiGYRj/FLNmwDAMw/iEhQHDMAwz+IQBEd1CRK1EtJeIHnP5fBgRrTE/30xE022f/Tfz/VYi+lYBtflviWgXEX1BRO8SUa3tsygRbTf/rS+gNt9PRCdsbXvQ9tkPiGiP+e8HBdTmf7W1dzcRnbZ9lq9+fo6IjhNRs8fnRET/w7ymL4hoge2zfPVzojbfZ7Z1JxF9RkSX2T47YL6/nYi2FlCbryeibtsYWG77LO64ymOb/97W3mZzDI81P0u+n4UQg+YfgACAfQDqAJQC2AFgrnLMXwN4yvz7bgBrzL/nmscPAzDD/J1AgbT5BgBl5t//WbbZfH22QPv5fgD/0+W7YwG0mf9Xmn9XFkKbleP/C4Dn8tnP5nmvBbAAQLPH598G8DYAAtAIYHM++9lnm6+SbQFwq2yz+foAgHEF2M/XA3gz3XGVyzYrx94O4L10+nmwaQZXAtgrhGgTQoQBvARgiXLMEgC/Nf9+BcCNRETm+y8JIfqEEPsB7DV/L+9tFkK8L4ToNV9uAlCdg3bFw08/e/EtAO8IIU4JIUIA3gFwS5baaSfZNt8D4MUctCsuQoiPAJyKc8gSAP8uDDYBGENEk5G/fk7YZiHEZ2abgMIYz3762Yt05kJaJNnmtMfzYBMGUwEctL3uNN9zPUYIEQHQDaDK53ezQbLnfQDGTlAynIi2EtEmIrojC+1zw2+bl5rmgFeIaFqS3800vs9rmuFmAHjP9nY++tkPXteVr35OFnU8CwB/IqImIno4T23yYjER7SCit4mo3nyv4PuZiMpgbATW2t5Oup+HzGMvBwNE9BcAFgK4zvZ2rRDiEBHVAXiPiHYKIfblp4UO3gDwohCij4gegaGNfSPPbfLL3QBeEUJEbe8Vaj8PWojoBhjC4Brb29eY/TwBwDtE9JW5A84322CMgbNE9G0A6wDMym+TfHM7gE+FEHYtIul+HmyawSEA02yvq833XI8hoiCACgBdPr+bDXydl4huAvAzAN8RQvTJ94UQh8z/2wB8AODybDbWJGGbhRBdtnY+C6DB73ezRDLnvRuKSp2nfvaD13Xlq599QURfgzEulgghuuT7tn4+DuA15MZUmxAhxBkhxFnz77cAlBDROBR4P5vEG8/++zkXjpAMOlSCMBxlMzDgzKlXjvkRnA7k35t/18PpQG5DbhzIftp8OQwn1Szl/UoAw8y/xwHYgxw4r3y2ebLt7+8C2GT+PRbAfrPtlebfYwuhzeZxl8BwrlG++9l2/unwdmz+b3A6kD/PZz/7bHMNDJ/cVcr7IwGU2/7+DMAtBdLmSXJMwFg4O8w+9zWu8tFm8/MKGH6Fken2c04uKMOd820Au83F82fmeyth7KgBYDiAl83B+DmAOtt3f2Z+rxXArQXU5g0AjgHYbv5bb75/FYCd5gDcCeCBAmrzfwfQYrbtfQCX2L77Q7P/9wL4T4XSZvP1CgCPK9/LZz+/COAIgH4Y9ugHADwK4FHzcwLwpHlNOwEsLIB+TtTmZwGEbON5q/l+ndnHO8yx87MCavOPbeN5E2yCzG1cFUKbzWPuhxEYY/9eSv3M5SgYhmGYQeczYBiGYbIACwOGYRiGhQHDMAzDwoBhGIYBCwOGYZiCIVFxOpfjv09GkcsWIlqd1rk5mohhGKYwIKJrAZyFUY9qXoJjZwH4PYBvCCFCRDRBGElmKcGaAcMwTIEgXIrTEdFMIvqDWWfoYyK6xPzoIQBPCrMoYDqCAGBhwDAMU+isAvBfhBANAP4OwP9rvn8xgIuJ6FOzwGJaVWu5UB3DMEyBQkSjYGTIv2xU4gdglNQBjPV7FoxnMVQD+IiILhVCnE7lXCwMGIZhChcNwGkhxHyXzzphPDioH8B+ItoNQzhsSfVEDMMwTAEihDgDY6G/C7AegyofI7oOhlYAs8LqxTCK6qUECwOGYZgCgYheBLARwGwi6iSiBwDcB+ABIpKF5+ST1v4IoIuIdsEoFvn3wlYuPOlzc2gpwzAMw5oBwzAMw8KAYRiGYWHAMAzDgIUBwzAMAxYGDMMwDFgYMAzDMGBhwDAMwwD4/wHlQQF6Kvi4MAAAAABJRU5ErkJggg==\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(torch.arange(0,len(conc2)), conc2, '.')" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x7ff7759c01f0>]" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(torch.arange(0,len(flat_fft2)), flat_fft2.abs(), '.')" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [], + "source": [ + "topk = torch.topk(\n", + " flat_fft2.abs(), round(0.1*len(flat_fft2)), dim=0, sorted=False\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.return_types.topk(\n", + "values=tensor([ 75.7603, 695.2839, 721.5375, ..., 68.1649, 68.1649, 68.1649]),\n", + "indices=tensor([294037, 1, 2, ..., 241565, 434039, 328013]))" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([294037, 1, 2, ..., 241565, 434039, 328013])" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk.indices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [], + "source": [ + "top10 = torch.zeros(len(flat_fft2), dtype = torch.cfloat)\n", + "top10[topk.indices] = flat_fft2[topk.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "84502" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(topk.indices)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "reverse_top10 = fft.irfft(top10)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(34.8182)" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_top10 - conc2, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc2, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(30254.6758)" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(reverse_top10 - conc2, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [], + "source": [ + "topk_og = torch.topk(\n", + " conc2.abs(), round(0.1*len(conc2)), dim=0, sorted=False\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "169005" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(topk_og.indices)" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 1, 2, 3, 4, 0, 6, 7, 8, 9, 10, 11, 12, 13, 16, 18, 19, 20, 21,\n", + " 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 40, 41, 42,\n", + " 44, 45, 46, 47, 48, 49, 39])" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk_og.indices[topk_og.indices<50]" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [], + "source": [ + "top10_og = torch.zeros(len(conc2))\n", + "top10_og[topk_og.indices] = conc2[topk_og.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(15.5541)" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - conc2, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(15858.2695)" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - conc2, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0058, -0.0441, -0.0381, -0.0493, -0.0240, 0.0190, -0.0132, -0.0221,\n", + " -0.0472, 0.0077, 0.0236, 0.0183, 0.0231, 0.0014, -0.0245, -0.0085,\n", + " 0.0035, -0.0036, 0.0150, 0.0107, 0.0123, 0.0039, 0.0003, -0.0320,\n", + " -0.0093, 0.0632, 0.0360, 0.0200, -0.0248, 0.0029, -0.0011, -0.0193,\n", + " 0.0221, 0.0056, -0.0091, -0.0008, 0.0329, 0.0133, -0.0078, -0.0061,\n", + " -0.0372, -0.0354, -0.0238, -0.0028, 0.0145, -0.0121, -0.0517, -0.0468,\n", + " -0.0123, -0.0132])" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse_top10[10000:10050]" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0155, 0.0128, -0.0386, 0.0186, 0.0166, 0.0259, -0.0200, -0.0033,\n", + " -0.0399, 0.0214, 0.0106, 0.0197, -0.0182, -0.0191, -0.0370, 0.0159,\n", + " 0.0071, -0.0321, -0.0166, -0.0082, 0.0090, 0.0291, 0.0117, 0.0011,\n", + " 0.0066, 0.0163, 0.0237, 0.0092, -0.0029, -0.0209, -0.0207, 0.0039,\n", + " 0.0065, 0.0057, 0.0316, -0.0262, -0.0342, -0.0115, 0.0149, -0.0175,\n", + " -0.0568, -0.0135, -0.0503, -0.0252, 0.0148, -0.0429, -0.0424, -0.0182,\n", + " -0.0002, -0.0341])" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "conc2 [10000:10050]" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0000, 0.0000, -0.0386, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " -0.0399, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, -0.0370, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " -0.0568, 0.0000, -0.0503, 0.0000, 0.0000, -0.0429, -0.0424, 0.0000,\n", + " 0.0000, 0.0000])" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top10_og[10000:10050]" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1440, -0.0482, 0.2070, ..., 0.0011, 0.0177, -0.0218])" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "conc2[0:10000]" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [], + "source": [ + "reverse_top10fft = reverse_top10" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Qho4AaaTgWEIKoaUkre85S1cffXVtLW1sXfvXgKBAP/93/89Yt94PM7s2bNHzB/Ix1//+tdxawbl45Of/CRbtmzh97//Pe9973tJJpMlPS6RSFR8LTpjMQQTuR6D8jGbBE01hs5QIXJHVoZOkBzB1K9gIvjbTdC5rbLP2bIWXn9rwbsfffRRHA4H//zP/wyoITW33XYbCxcu5POf/zy/+93v+OMf/0ggECCRSHD33Xdz5ZVXsn37dkKhEDfccAPbt29n+fLlHD9+nDvvvJMNGzbQ2trK5s2bCQQCvP71r+f888/n2WefZc6cOdx///1UVVXxox/9iB/+8IdEo1GWLFnCz3/+85LnBaxcuRKLxUJvby833ngjR48eJRwO84lPfIIbb7wRAJfLxb/8y7/w8MMPc+edd/Loo4/ypz/9ieHhYc4991x+8IMfIIRg48aNnHrqqTz11FMEg0F+9rOf8ZWvfIVt27bxjne8g1tuuQWAX/ziF9xxxx1Eo1HOOussvvvd7/Lf//3fKfXW1atX88tf/jLvfmazecR6/vznP/PAAw9gsVi49NJL83pBBgYnAnpTma5CqkJDU38aNjyCCrFjxw5OP/30rG1ut5v58+ezb98+AF5++WXuuecennjiiaz9vvvd71JbW8vOnTv54he/yEsvvZT3GG1tbXzkIx9hx44deL1e/vCHPwDwlre8hRdffJGtW7eycuVK/u///q/kdW/atAmTyURjYyM/+clPeOmll9i8eTN33HEHfX19AASDQc466yy2bt3K+eefz0c/+lFefPFFtm/fzvDwcJayqs1mY/PmzXzwgx/kTW96E3feeSfbt2/nrrvuoq+vj127dvHb3/6WZ555hi1btmA2m/nlL3/JrbfemlJv/eUvf1lwv9z1rFy5knvvvZcdO3bw6quv8tnPfrbk125gMNnUV9uwmkXKIwhE4lMuQQ3T1SMocuU+lVxyySXU1dWN2P7000/ziU98AoA1a9awbt26vI9fuHAh69evB+D000/n0KFDAGzfvp3PfvazDA4OEggEuOyyy0Zdy2233cYvfvELampq+O1vf4sQgjvuuIN7770XgKNHj9LW1kZ9fT1ms5m3vvWtqcc+9thjfO1rXyMUCtHf38/q1at54xvfCCgBO4C1a9eyevXqlHjdokWLOHr0KE8//TQvvfQSZ5xxBqBmODQ1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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(np.arange(100000,100050,1), reverse_top10fft[100000:100050], label = \"FFT top-10%\")\n", + "plt.plot(np.arange(100000,100050,1), conc2[100000:100050], label = \"Original Parameters\")\n", + "plt.plot(np.arange(100000,100050,1), top10_og[100000:100050], label = \"Parameter top-10%\")\n", + "plt.title('Parameter Values') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.legend()\n", + "plt.draw()\n", + "plt.savefig(\"Parameters.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(conc2.numpy(), 100, (-0.1,0.1))\n", + "plt.title('Parameter Values Histogram') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter values\")\n", + "plt.draw()\n", + "plt.savefig(\"Parameter_Histogram.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(reverse_top10.numpy(), 100, (-0.1,0.1))\n", + "plt.title('Top-10% FFT Reconstructed Parameter Values Histogram') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter values\")\n", + "plt.draw()\n", + "plt.savefig(\"FFT_Histogram.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(top10_og[top10_og.abs() >0].numpy(), 100, (-0.1,0.1))\n", + "plt.title('Top-10% Parameter Values Histogram') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter values\")\n", + "plt.draw()\n", + "plt.savefig(\"top10_Histogram.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.14400896, -0.04817872, 0.20703338, ..., 0.0729612 ,\n", + " -0.06001848, -0.03798665], dtype=float32)" + ] + }, + "execution_count": 86, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top10_og[top10_og.abs() >0].numpy()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Per Layer" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": {}, + "outputs": [], + "source": [ + "flat5000 = []\n", + "for v in weights[\"17000\"].values():\n", + " flat5000.append(v.flatten())\n", + "conc500 = torch.cat(flat5000)" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc500, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 134, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(3.8334)\n", + "tensor(0.5911)\n", + "tensor(14.2745)\n", + "tensor(0.2714)\n", + "tensor(29.4115)\n", + "tensor(0.4823)\n", + "tensor(9.3226)\n", + "tensor(0.3447)\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "errs = []\n", + "lens = []\n", + "fft_layers = []\n", + "for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " lens.append(len(flat))\n", + " flat_fft = fft.rfft(flat)\n", + " topk = torch.topk(\n", + " flat_fft.abs(), round(0.1*len(flat_fft)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + " top10[topk.indices] = flat_fft[topk.indices]\n", + " reverse_top10 = fft.irfft(top10)\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " print(err)\n", + " errs.append(err*err)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[800, 32, 51200, 64, 1605632, 512, 31744, 62]" + ] + }, + "execution_count": 135, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lens" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1171.1743" + ] + }, + "execution_count": 136, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 137, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "34.222424" + ] + }, + "execution_count": 137, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [], + "source": [ + "fft_conc = torch.cat(fft_layers)" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'conc5000' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [94]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m torch\u001b[38;5;241m.\u001b[39mnorm(fft_conc \u001b[38;5;241m-\u001b[39m \u001b[43mconc5000\u001b[49m\n\u001b[1;32m 2\u001b[0m ,\u001b[38;5;241m2\u001b[39m)\n", + "\u001b[0;31mNameError\u001b[0m: name 'conc5000' is not defined" + ] + } + ], + "source": [ + "torch.norm(fft_conc - conc5000\n", + " ,2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Almost no difference in layerwise vs over the entire weight" + ] + }, + { + "cell_type": "code", + "execution_count": 138, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['0', '500', '1000', '1500', '2000', '2500', '3000', '3500', '4000', '4500', '5000', '5500', '6000', '6500', '7000', '7500', '8000', '8500', '9000', '9500', '10000', '10500', '11000', '11500', '12000', '12500', '13000', '13500', '14000', '14500', '15000', '15500', '16000', '16500', '17000'])" + ] + }, + "execution_count": 138, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weights.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 139, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(3.8017)\n", + "tensor(0.6525)\n", + "tensor(9.6627)\n", + "tensor(0.2314)\n", + "tensor(14.0121)\n", + "tensor(0.3602)\n", + "tensor(6.0212)\n", + "tensor(0.3187)\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "errs = []\n", + "lens = []\n", + "for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " lens.append(len(flat))\n", + " topk = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat))\n", + " top10[topk.indices] = flat[topk.indices]\n", + " err = torch.norm(top10 - flat, 2)\n", + " print(err)\n", + " errs.append(err*err)" + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[800, 32, 51200, 64, 1605632, 512, 31744, 62]" + ] + }, + "execution_count": 140, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lens" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 141, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "341.1233" + ] + }, + "execution_count": 141, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 142, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "18.469522" + ] + }, + "execution_count": 142, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [], + "source": [ + "flat5000 = []\n", + "for v in weights[\"17000\"].values():\n", + " flat5000.append(v.flatten())\n", + "conc5000 = torch.cat(flat5000)" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 100, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc5000, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(2.5049)\n", + "tensor(0.4643)\n", + "tensor(6.6074)\n", + "tensor(0.1233)\n", + "tensor(12.2971)\n", + "tensor(0.1902)\n", + "tensor(4.0843)\n", + "tensor(0.1482)\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "errs = []\n", + "errs1 = []\n", + "lens = []\n", + "fft_layers = []\n", + "for v in weights[\"1000\"].values():\n", + " flat = v.flatten()\n", + " lens.append(len(flat))\n", + " flat_fft = fft.rfft(flat)\n", + " topk = torch.topk(\n", + " flat_fft.abs(), round(0.2*len(flat_fft)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + " top10[topk.indices] = flat_fft[topk.indices]\n", + " reverse_top10 = fft.irfft(top10)\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " errs1.append(torch.norm(reverse_top10 - flat, 1))\n", + " print(err)\n", + " errs.append(err*err)" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[800, 32, 51200, 64, 1605632, 512, 31744, 62]" + ] + }, + "execution_count": 102, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lens" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "218.12065" + ] + }, + "execution_count": 103, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "14.7689085" + ] + }, + "execution_count": 104, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": {}, + "outputs": [], + "source": [ + "fft_conc = torch.cat(fft_layers)" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(39.6843)" + ] + }, + "execution_count": 106, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(fft_conc - conc5000,2)" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[tensor(57.1960),\n", + " tensor(2.2182),\n", + " tensor(1148.8655),\n", + " tensor(0.7960),\n", + " tensor(12109.6943),\n", + " tensor(3.3738),\n", + " tensor(578.7853),\n", + " tensor(0.9163)]" + ] + }, + "execution_count": 107, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "errs1" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "13901.846" + ] + }, + "execution_count": 108, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs1)" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(3.8017)\n", + "tensor(0.6525)\n", + "tensor(9.6627)\n", + "tensor(0.2314)\n", + "tensor(14.0121)\n", + "tensor(0.3602)\n", + "tensor(6.0212)\n", + "tensor(0.3187)\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "errs = []\n", + "lens = []\n", + "errs1 = []\n", + "for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " lens.append(len(flat))\n", + " topk = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat))\n", + " top10[topk.indices] = flat[topk.indices]\n", + " err = torch.norm(top10 - flat, 2)\n", + " print(err)\n", + " errs.append(err*err)\n", + " errs1.append(torch.norm(top10 - flat, 1))" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[800, 32, 51200, 64, 1605632, 512, 31744, 62]" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lens" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "341.1233" + ] + }, + "execution_count": 111, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 112, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "18.469522" + ] + }, + "execution_count": 112, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[tensor(86.4496),\n", + " tensor(3.1551),\n", + " tensor(1531.9570),\n", + " tensor(1.5015),\n", + " tensor(14199.5361),\n", + " tensor(6.1879),\n", + " tensor(814.4448),\n", + " tensor(2.0511)]" + ] + }, + "execution_count": 113, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "errs1" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "16645.283" + ] + }, + "execution_count": 114, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sum(errs1)" + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n", + "None\n", + "None\n", + "None\n", + "None\n", + "None\n", + "None\n", + "None\n" + ] + } + ], + "source": [ + "flat5000 = []\n", + "for v in weights[\"17000\"].values():\n", + " print(v.grad)\n", + " flat5000.append(v.flatten())\n", + "conc5000 = torch.cat(flat5000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Wavelets <a class=\"anchor\" id=\"wt\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: PyWavelets in /home/jeffrey/anaconda3/envs/sacs39/lib/python3.9/site-packages (1.2.0)\n", + "Requirement already satisfied: numpy>=1.17.3 in /home/jeffrey/anaconda3/envs/sacs39/lib/python3.9/site-packages (from PyWavelets) (1.22.3)\n" + ] + } + ], + "source": [ + "!pip install PyWavelets" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [], + "source": [ + "import pywt" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "metadata": {}, + "outputs": [], + "source": [ + "#(cA, cD) = pywt.dwt(, 'db1')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# pywt.wavelist(kind='discrete', )" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 18.427034\n", + "db1 18.427034\n", + "sym2 18.36348\n", + "coif1 18.393574\n", + "bior1.1 18.427034\n", + "rbio1.1 18.427034\n", + "dmey 18.671127\n", + "bior4.4 18.496372\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "for wavelet in wavelets:\n", + " errs = []\n", + " errs1 = []\n", + " lens = []\n", + " fft_layers = []\n", + " for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " #print(flat.shape)\n", + " lens.append(len(flat))\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " errs1.append(torch.norm(reverse_top10 - flat, 1))\n", + " #print(err)\n", + " errs.append(err*err)\n", + " # print(flat[0:10])\n", + " # print(reverse_top10[0:10])\n", + " print(wavelet, np.sqrt(np.sum(errs)))" + ] + }, + { + "cell_type": "code", + "execution_count": 156, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bior1.1 15.07145881652832 16107.921875\n", + "bior1.3 15.25814437866211 16279.986328125\n", + "bior1.5 15.425777435302734 16436.12109375\n", + "bior2.2 15.66141128540039 16473.904296875\n", + "bior2.4 15.516386985778809 16417.8203125\n", + "bior2.6 15.544709205627441 16466.162109375\n", + "bior2.8 15.579778671264648 16503.138671875\n", + "bior3.1 25.344850540161133 24354.4453125\n", + "bior3.3 18.38104248046875 18552.30859375\n", + "bior3.5 17.479848861694336 17874.1015625\n", + "bior3.7 17.260520935058594 17713.20703125\n", + "bior3.9 17.19255828857422 17672.990234375\n", + "bior4.4 15.1978120803833 16241.7060546875\n", + "bior5.5 15.467646598815918 16527.41796875\n", + "bior6.8 15.204909324645996 16253.8125\n", + "coif1 15.142683029174805 16156.6630859375\n", + "coif2 15.175430297851562 16219.298828125\n", + "coif3 15.218149185180664 16275.017578125\n", + "coif4 15.248283386230469 16304.376953125\n", + "coif5 15.278726577758789 16337.1923828125\n", + "coif6 15.300649642944336 16357.455078125\n", + "coif7 15.324337005615234 16380.2119140625\n", + "coif8 15.34239387512207 16396.9453125\n", + "coif9 15.35299301147461 16408.88671875\n", + "coif10 15.358224868774414 16412.31640625\n", + "coif11 15.375347137451172 16429.083984375\n", + "coif12 15.383316993713379 16440.47265625\n", + "coif13 15.401575088500977 16450.142578125\n", + "coif14 15.413949012756348 16466.5859375\n", + "coif15 15.430389404296875 16478.208984375\n", + "coif16 15.438526153564453 16489.732421875\n", + "coif17 15.44447135925293 16493.5625\n", + "db1 15.07145881652832 16107.921875\n", + "db2 15.11799430847168 16146.3642578125\n", + "db3 15.206748008728027 16251.126953125\n", + "db4 15.276558876037598 16337.6650390625\n", + "db5 15.346190452575684 16396.228515625\n", + "db6 15.424012184143066 16471.95703125\n", + "db7 15.465736389160156 16520.9609375\n", + "db8 15.5084228515625 16558.216796875\n", + "db9 15.579204559326172 16622.1484375\n", + "db10 15.634806632995605 16672.583984375\n", + "db11 15.69124698638916 16721.88671875\n", + "db12 15.76386833190918 16791.78125\n", + "db13 15.807873725891113 16828.6328125\n", + "db14 15.84904956817627 16859.560546875\n", + "db15 15.879130363464355 16884.310546875\n", + "db16 15.916594505310059 16917.77734375\n", + "db17 15.97330093383789 16964.7890625\n", + "db18 16.010889053344727 17004.966796875\n", + "db19 16.06007957458496 17043.080078125\n", + "db20 16.109506607055664 17080.361328125\n", + "db21 16.15558433532715 17122.78125\n", + "db22 16.195322036743164 17152.8046875\n", + "db23 16.23825454711914 17190.244140625\n", + "db24 16.28815269470215 17229.99609375\n", + "db25 16.29660415649414 17237.244140625\n", + "db26 16.331958770751953 17263.62890625\n", + "db27 16.375545501708984 17302.498046875\n", + "db28 16.413320541381836 17331.599609375\n", + "db29 16.437959671020508 17352.27734375\n", + "db30 16.50661849975586 17411.228515625\n", + "db31 16.53733253479004 17433.791015625\n", + "db32 16.5701904296875 17458.037109375\n", + "db33 16.599777221679688 17484.1953125\n", + "db34 16.628063201904297 17505.951171875\n", + "db35 16.64190101623535 17514.66796875\n", + "db36 16.680456161499023 17541.33203125\n", + "db37 16.730104446411133 17587.6328125\n", + "db38 16.75263214111328 17598.830078125\n", + "dmey 15.428367614746094 16479.267578125\n", + "haar 15.07145881652832 16107.921875\n", + "rbio1.1 15.07145881652832 16107.921875\n", + "rbio1.3 15.1613130569458 16189.78125\n", + "rbio1.5 15.32840633392334 16338.216796875\n", + "rbio2.2 16.183170318603516 16984.47265625\n", + "rbio2.4 15.833732604980469 16793.46875\n", + "rbio2.6 15.841042518615723 16820.513671875\n", + "rbio2.8 15.870935440063477 16858.255859375\n", + "rbio3.1 112.47295379638672 58394.6875\n", + "rbio3.3 19.817306518554688 20010.50390625\n", + "rbio3.5 18.20765495300293 18729.5625\n", + "rbio3.7 17.90874671936035 18495.369140625\n", + "rbio3.9 17.855627059936523 18441.083984375\n", + "rbio4.4 15.365104675292969 16364.685546875\n", + "rbio5.5 15.447882652282715 16390.2890625\n", + "rbio6.8 15.320694923400879 16363.552734375\n", + "sym2 15.11799430847168 16146.3642578125\n", + "sym3 15.206748008728027 16251.126953125\n", + "sym4 15.159475326538086 16207.3779296875\n", + "sym5 15.204032897949219 16260.142578125\n", + "sym6 15.191091537475586 16246.744140625\n", + "sym7 15.236370086669922 16293.701171875\n", + "sym8 15.241791725158691 16298.5556640625\n", + "sym9 15.26644229888916 16327.4296875\n", + "sym10 15.264242172241211 16323.5576171875\n", + "sym11 15.332569122314453 16396.794921875\n", + "sym12 15.310770034790039 16371.40234375\n", + "sym13 15.304075241088867 16360.4248046875\n", + "sym14 15.317804336547852 16377.61328125\n", + "sym15 15.378673553466797 16436.265625\n", + "sym16 15.33505916595459 16392.92578125\n", + "sym17 15.344695091247559 16404.30859375\n", + "sym18 15.363746643066406 16418.08984375\n", + "sym19 15.430442810058594 16479.15625\n", + "sym20 15.377063751220703 16438.19140625\n", + "min: tensor(15.0715) bior1.1 0\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "#wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " for v in weights[\"17000\"].values():\n", + " flat = v.flatten()\n", + " #print(flat.shape)\n", + " lens.append(len(flat))\n", + " to_cat.append(flat)\n", + " flat = torch.cat(to_cat, dim=0)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 157, + "metadata": {}, + "outputs": [], + "source": [ + "topk_og = torch.topk(\n", + " conc2.abs(), round(0.1*len(conc2)), dim=0, sorted=False\n", + " )\n", + "top10_og = torch.zeros(len(conc2))\n", + "top10_og[topk_og.indices] = conc2[topk_og.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 158, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(15.5541)" + ] + }, + "execution_count": 158, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - conc2, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 159, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "42.212055" + ] + }, + "execution_count": 159, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(np.sum(errs))" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "# Problem: weights with only a few parameters cannot be represented with the wavelets" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "metadata": {}, + "outputs": [], + "source": [ + "flat5000 = []\n", + "for v in weights[\"17000\"].values():\n", + " flat5000.append(v.flatten())\n", + "conc5000 = torch.cat(flat5000)" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(44.8886)" + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(conc5000, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 149, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dmey tensor(15.4284)\n" + ] + } + ], + "source": [ + "wavelet = 'dmey'\n", + "coeff = pywt.wavedec(conc5000.numpy(), wavelet, level = None)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))" + ] + }, + { + "cell_type": "code", + "execution_count": 150, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(np.arange(100000,100050,1), reverse_top10fft[100000:100050], label = \"FFT top-10%\")\n", + "plt.plot(np.arange(100000,100050,1), conc2[100000:100050], label = \"Original Parameters\")\n", + "plt.plot(np.arange(100000,100050,1), reverse_top10[100000:100050], label = \"Haar top-10%\")\n", + "plt.title('Parameter Values') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.legend()\n", + "plt.draw()\n", + "plt.savefig(\"ParametersWaveletHaar.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 175, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar tensor(12.0875)\n" + ] + } + ], + "source": [ + "wavelet = 'haar'\n", + "coeff = pywt.wavedec(conc5000.numpy(), wavelet, level = None)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))" + ] + }, + { + "cell_type": "code", + "execution_count": 176, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar tensor(9.4642)\n" + ] + } + ], + "source": [ + "wavelet = 'haar'\n", + "coeff = pywt.wavedec(conc5000.numpy(), wavelet, level = None)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.2*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))" + ] + }, + { + "cell_type": "code", + "execution_count": 177, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "haar tensor(12.1470)\n", + "(52814,)\n", + "(52814,)\n", + "(105628,)\n", + "(211256,)\n", + "(422512,)\n", + "(845023,)\n", + "haar tensor(16.9818)\n", + "(52814,)\n", + "(52814,)\n", + "(105628,)\n", + "(211256,)\n", + "(422512,)\n", + "(845023,)\n", + "haar tensor(2.3811e-06)\n" + ] + } + ], + "source": [ + "wavelet = 'haar'\n", + "coeff = pywt.wavedec(conc5000.numpy(), wavelet, level = 5)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "print(len(coeff))\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))\n", + "\n", + "reduced = []\n", + "for i, o in enumerate(coeff):\n", + " print(o.shape) \n", + " if i > 3:\n", + " reduced.append(np.zeros_like(o))\n", + " continue\n", + " reduced.append(o)\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(reduced, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))\n", + "\n", + "reduced = []\n", + "for i, o in enumerate(coeff):\n", + " print(o.shape) \n", + " if i > 5:\n", + " reduced.append(np.zeros_like(o))\n", + " continue\n", + " reduced.append(o)\n", + "reverse_top10 = torch.from_numpy(pywt.waverec(reduced, wavelet = wavelet))\n", + "print(wavelet, torch.norm(conc5000 - reverse_top10, 2))\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# with resnet" + ] + }, + { + "cell_type": "code", + "execution_count": 178, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using cache found in /home/jeffrey/.cache/torch/hub/pytorch_vision_v0.10.0\n" + ] + } + ], + "source": [ + "model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 179, + "metadata": {}, + "outputs": [], + "source": [ + "resw = {}\n", + "for k,v in model.state_dict().items():\n", + " resw[k] = v.clone()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "flatr = []\n", + "for v in resw.values():\n", + " flatr.append(v.flatten())\n", + "concr = torch.cat(flatr)" + ] + }, + { + "cell_type": "code", + "execution_count": 190, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bior1.1 43.02796936035156 115077.1953125\n", + "bior1.3 44.042415618896484 117252.8203125\n", + "bior1.5 44.798824310302734 119106.71875\n", + "bior2.2 44.7282600402832 117956.5\n", + "bior2.4 44.04926300048828 116528.5078125\n", + "bior2.6 44.09769821166992 116693.171875\n", + "bior2.8 44.207454681396484 116984.125\n", + "bior3.1 65.93879699707031 171188.890625\n", + "bior3.3 52.62727355957031 136826.25\n", + "bior3.5 50.10884475708008 130465.40625\n", + "bior3.7 49.333717346191406 128473.21875\n", + "bior3.9 49.07342529296875 127796.1640625\n", + "bior4.4 42.742881774902344 114508.9921875\n", + "bior5.5 43.98085403442383 118580.4296875\n", + "bior6.8 42.57365417480469 113812.046875\n", + "coif1 42.74231719970703 114690.046875\n", + "coif2 42.56312561035156 114001.890625\n", + "coif3 42.54220199584961 113903.578125\n", + "coif4 42.558956146240234 113906.859375\n", + "coif5 42.56120681762695 113924.28125\n", + "coif6 42.592472076416016 113980.0390625\n", + "coif7 42.60406494140625 114030.09375\n", + "coif8 42.61618423461914 114052.2734375\n", + "coif9 42.6173095703125 114053.078125\n", + "coif10 42.63934326171875 114081.7890625\n", + "coif11 42.65342712402344 114141.3671875\n", + "coif12 42.65858840942383 114128.3984375\n", + "coif13 42.66160583496094 114154.7890625\n", + "coif14 42.68099594116211 114187.8828125\n", + "coif15 42.693885803222656 114239.90625\n", + "coif16 42.69415283203125 114222.0234375\n", + "coif17 42.69487762451172 114230.65625\n", + "db1 43.02796936035156 115077.1953125\n", + "db2 42.69436264038086 114436.171875\n", + "db3 42.692832946777344 114409.2578125\n", + "db4 42.69171905517578 114270.2265625\n", + "db5 42.7407341003418 114356.6796875\n", + "db6 42.832889556884766 114583.046875\n", + "db7 42.90106201171875 114756.140625\n", + "db8 42.927757263183594 114787.8671875\n", + "db9 42.980587005615234 114925.3125\n", + "db10 43.0425910949707 115035.796875\n", + "db11 43.09166717529297 115145.9609375\n", + "db12 43.11075210571289 115177.953125\n", + "db13 43.153038024902344 115282.9765625\n", + "db14 43.23004913330078 115438.109375\n", + "db15 43.254371643066406 115495.4375\n", + "db16 43.26611328125 115499.40625\n", + "db17 43.29021453857422 115553.8359375\n", + "db18 43.339332580566406 115670.8515625\n", + "db19 43.363834381103516 115699.546875\n", + "db20 43.3875732421875 115747.3046875\n", + "db21 43.406944274902344 115809.53125\n", + "db22 43.44538879394531 115883.546875\n", + "db23 43.48051071166992 115981.046875\n", + "db24 43.502601623535156 115997.3203125\n", + "db25 43.519954681396484 116035.3359375\n", + "db26 43.53356170654297 116078.15625\n", + "db27 43.55718994140625 116114.859375\n", + "db28 43.56884765625 116135.7421875\n", + "db29 43.60223388671875 116207.0390625\n", + "db30 43.6269645690918 116254.625\n", + "db31 43.62778091430664 116261.8984375\n", + "db32 43.65283966064453 116317.5546875\n", + "db33 43.683868408203125 116371.8046875\n", + "db34 43.71052551269531 116451.03125\n", + "db35 43.69470977783203 116395.71875\n", + "db36 43.722896575927734 116448.71875\n", + "db37 43.732479095458984 116494.3203125\n", + "db38 43.75498962402344 116516.2890625\n", + "dmey 42.70671844482422 114251.421875\n", + "haar 43.02796936035156 115077.1953125\n", + "rbio1.1 43.02796936035156 115077.1953125\n", + "rbio1.3 42.904876708984375 114998.609375\n", + "rbio1.5 43.487056732177734 116603.4375\n", + "rbio2.2 48.12295150756836 128830.65625\n", + "rbio2.4 45.82650375366211 123338.625\n", + "rbio2.6 45.57454299926758 122649.625\n", + "rbio2.8 45.610652923583984 122736.25\n", + "rbio3.1 323.1489562988281 493834.4375\n", + "rbio3.3 63.0237922668457 168654.40625\n", + "rbio3.5 55.14375686645508 147856.1875\n", + "rbio3.7 53.33525466918945 143081.296875\n", + "rbio3.9 52.70606994628906 141449.8125\n", + "rbio4.4 43.57114028930664 116553.6171875\n", + "rbio5.5 43.684425354003906 115561.5078125\n", + "rbio6.8 43.01945495605469 115265.328125\n", + "sym2 42.69436264038086 114436.171875\n", + "sym3 42.692832946777344 114409.2578125\n", + "sym4 42.546844482421875 113956.859375\n", + "sym5 42.57182693481445 113959.1640625\n", + "sym6 42.52703094482422 113885.0546875\n", + "sym7 42.550376892089844 113925.90625\n", + "sym8 42.56036376953125 113907.7109375\n", + "sym9 42.602020263671875 114008.0625\n", + "sym10 42.568580627441406 113940.015625\n", + "sym11 42.623958587646484 114091.0546875\n", + "sym12 42.602752685546875 114007.203125\n", + "sym13 42.62556076049805 114069.9375\n", + "sym14 42.608367919921875 114038.21875\n", + "sym15 42.66935348510742 114179.7578125\n", + "sym16 42.629066467285156 114064.859375\n", + "sym17 42.639869689941406 114103.421875\n", + "sym18 42.6433219909668 114109.6328125\n", + "sym19 42.72231674194336 114301.625\n", + "sym20 42.658966064453125 114131.046875\n", + "min: tensor(42.5270) sym6 91\n" + ] + } + ], + "source": [ + "# working on the random initialization\n", + "#wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " for v in resw.values():\n", + " flat = v.flatten()\n", + " #print(flat.shape)\n", + " lens.append(len(flat))\n", + " to_cat.append(flat)\n", + " flat = torch.cat(to_cat, dim=0)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " fft_layers.append(reverse_top10)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 181, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "11699132" + ] + }, + "execution_count": 181, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(concr)" + ] + }, + { + "cell_type": "code", + "execution_count": 197, + "metadata": {}, + "outputs": [], + "source": [ + "topk_og = torch.topk(\n", + " concr.abs(), round(0.1*len(concr)), dim=0, sorted=False\n", + " )\n", + "top10_og = torch.zeros(len(concr))\n", + "top10_og[topk_og.indices] = concr[topk_og.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 198, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(47.3773)" + ] + }, + "execution_count": 198, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - concr, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 199, + "metadata": {}, + "outputs": [], + "source": [ + "to_cat = []\n", + "for v in resw.values():\n", + " flat = v.flatten()\n", + " to_cat.append(flat)\n", + "flat = torch.cat(to_cat, dim=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 200, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(71.3879)\n" + ] + } + ], + "source": [ + "flat_fft = fft.rfft(flat)\n", + "topk = torch.topk(\n", + " flat_fft.abs(), round(0.1*len(flat_fft)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + "top10[topk.indices] = flat_fft[topk.indices]\n", + "reverse_top10fft = fft.irfft(top10)\n", + "fft_layers.append(reverse_top10fft)\n", + "err = torch.norm(reverse_top10fft - flat, 2)\n", + "print(err)" + ] + }, + { + "cell_type": "code", + "execution_count": 201, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(42.6944)\n" + ] + } + ], + "source": [ + "coeff = pywt.wavedec(flat.numpy(), \"sym2\", level = None)\n", + "array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + "#print(coeff_slices) # should be static so we do not need to send them\n", + "topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + "top10 = torch.zeros(len(array))\n", + "top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + "og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + "reverse_top10wv = torch.from_numpy(pywt.waverec(og, wavelet = \"sym2\"))\n", + "err = torch.norm(reverse_top10wv - flat, 2)\n", + "print(err)" + ] + }, + { + "cell_type": "code", + "execution_count": 202, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(np.arange(100000,100050,1), reverse_top10fft[100000:100050], label = \"FFT top-10%\")\n", + "plt.plot(np.arange(100000,100050,1), concr[100000:100050], label = \"Original Parameters\")\n", + "plt.plot(np.arange(100000,100050,1), reverse_top10wv[100000:100050], label = \"Sym2 top-10%\")\n", + "\n", + "plt.title('Parameter Values') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.legend()\n", + "plt.draw()\n", + "plt.savefig(\"ParametersWaveletHaar.png\")" + ] + }, + { + "cell_type": "code", + "execution_count": 203, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0000, 0.0649, 0.0881, 0.0000, 0.0464, 0.0347, -0.0472, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, -0.0365, 0.0000,\n", + " -0.0422, -0.0344, 0.0372, -0.0823, 0.0000, 0.0764, -0.1654, 0.0000,\n", + " 0.0000, -0.0363, -0.0769, 0.0896, 0.0000, 0.0955, 0.0000, -0.0843,\n", + " 0.0000, -0.0387, 0.1598, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000])" + ] + }, + "execution_count": 203, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top10_og[100000:100050]" + ] + }, + { + "cell_type": "code", + "execution_count": 204, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(np.arange(1000000,1000050,1), reverse_top10fft[1000000:1000050], label = \"FFT top-10%\")\n", + "plt.plot(np.arange(1000000,1000050,1), concr[1000000:1000050], label = \"Original Parameters\")\n", + "plt.plot(np.arange(1000000,1000050,1), reverse_top10wv[1000000:1000050], label = \"Sym2 top-10%\")\n", + "\n", + "plt.title('Parameter Values') \n", + "#plt.ylabel(\"Absolute frequency value\")\n", + "plt.xlabel(\"Parameter indices\")\n", + "plt.legend()\n", + "plt.draw()\n", + "plt.savefig(\"ParametersWaveletHaar.png\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## FFT Training<a class=\"anchor\" id=\"ffttrain\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": { + "id": "e65Izyv0s-yE" + }, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "eqOXilqMs-yF", + "outputId": "06799a3b-983b-4f51-a7bd-a901c041bd05" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.136391 [ 0/735856]\n", + "loss: 1.387546 [64000/735856]\n", + "loss: 1.009362 [128000/735856]\n", + "loss: 0.568759 [192000/735856]\n", + "loss: 0.796950 [256000/735856]\n", + "loss: 0.670068 [320000/735856]\n", + "loss: 0.625332 [384000/735856]\n", + "loss: 0.557147 [448000/735856]\n", + "loss: 0.701893 [512000/735856]\n", + "loss: 0.670033 [576000/735856]\n", + "loss: 0.575888 [640000/735856]\n", + "loss: 0.654841 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 82.0%, Avg loss: 0.578153 \n", + "\n", + "loss: 0.776733 [ 0/735856]\n", + "loss: 0.519993 [64000/735856]\n", + "loss: 0.599282 [128000/735856]\n", + "loss: 0.885723 [192000/735856]\n", + "loss: 0.514714 [256000/735856]\n", + "loss: 0.539040 [320000/735856]\n", + "loss: 0.422559 [384000/735856]\n", + "loss: 0.382564 [448000/735856]\n", + "loss: 0.412677 [512000/735856]\n", + "loss: 0.360731 [576000/735856]\n", + "loss: 0.534333 [640000/735856]\n", + "loss: 0.379236 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.1%, Avg loss: 0.463718 \n", + "\n", + "loss: 0.367664 [ 0/735856]\n", + "loss: 0.339760 [64000/735856]\n", + "loss: 0.653718 [128000/735856]\n", + "loss: 0.410070 [192000/735856]\n", + "loss: 0.554535 [256000/735856]\n", + "loss: 0.578007 [320000/735856]\n", + "loss: 0.421670 [384000/735856]\n", + "loss: 0.599983 [448000/735856]\n", + "loss: 0.262858 [512000/735856]\n", + "loss: 0.333737 [576000/735856]\n", + "loss: 0.361296 [640000/735856]\n", + "loss: 0.468058 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.9%, Avg loss: 0.420345 \n", + "\n", + "loss: 0.443198 [ 0/735856]\n", + "loss: 0.507409 [64000/735856]\n", + "loss: 0.554008 [128000/735856]\n", + "loss: 0.304086 [192000/735856]\n", + "loss: 0.482780 [256000/735856]\n", + "loss: 0.349616 [320000/735856]\n", + "loss: 0.402055 [384000/735856]\n", + "loss: 0.345523 [448000/735856]\n", + "loss: 0.364194 [512000/735856]\n", + "loss: 0.310542 [576000/735856]\n", + "loss: 0.441185 [640000/735856]\n", + "loss: 0.276955 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.8%, Avg loss: 0.390410 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " topk = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat))\n", + " top10[topk.indices] = flat[topk.indices]\n", + " g.grad = top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# it converges slower than without gradient compression" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "import torch.fft as fft" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.122382 [ 0/735856]\n", + "loss: 1.659356 [64000/735856]\n", + "loss: 1.175072 [128000/735856]\n", + "loss: 1.030752 [192000/735856]\n", + "loss: 0.891644 [256000/735856]\n", + "loss: 0.732518 [320000/735856]\n", + "loss: 0.613185 [384000/735856]\n", + "loss: 0.483264 [448000/735856]\n", + "loss: 0.580724 [512000/735856]\n", + "loss: 0.509457 [576000/735856]\n", + "loss: 0.661517 [640000/735856]\n", + "loss: 0.621521 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 81.7%, Avg loss: 0.570322 \n", + "\n", + "loss: 0.543810 [ 0/735856]\n", + "loss: 0.339085 [64000/735856]\n", + "loss: 0.495473 [128000/735856]\n", + "loss: 0.384833 [192000/735856]\n", + "loss: 0.418521 [256000/735856]\n", + "loss: 0.614597 [320000/735856]\n", + "loss: 0.515266 [384000/735856]\n", + "loss: 0.738823 [448000/735856]\n", + "loss: 0.423178 [512000/735856]\n", + "loss: 0.473593 [576000/735856]\n", + "loss: 0.518021 [640000/735856]\n", + "loss: 0.497685 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 84.0%, Avg loss: 0.474809 \n", + "\n", + "loss: 0.575689 [ 0/735856]\n", + "loss: 0.456497 [64000/735856]\n", + "loss: 0.429356 [128000/735856]\n", + "loss: 0.563055 [192000/735856]\n", + "loss: 0.486054 [256000/735856]\n", + "loss: 0.542747 [320000/735856]\n", + "loss: 0.441926 [384000/735856]\n", + "loss: 0.461542 [448000/735856]\n", + "loss: 0.502812 [512000/735856]\n", + "loss: 0.383888 [576000/735856]\n", + "loss: 0.266721 [640000/735856]\n", + "loss: 0.490470 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.8%, Avg loss: 0.423047 \n", + "\n", + "loss: 0.302303 [ 0/735856]\n", + "loss: 0.421864 [64000/735856]\n", + "loss: 0.376742 [128000/735856]\n", + "loss: 0.259237 [192000/735856]\n", + "loss: 0.368860 [256000/735856]\n", + "loss: 0.400204 [320000/735856]\n", + "loss: 0.310619 [384000/735856]\n", + "loss: 0.320007 [448000/735856]\n", + "loss: 0.305337 [512000/735856]\n", + "loss: 0.375540 [576000/735856]\n", + "loss: 0.362421 [640000/735856]\n", + "loss: 0.347816 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.3%, Avg loss: 0.400034 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " \n", + " flat_fft = fft.rfft(flat)\n", + " topk = torch.topk(flat_fft.abs(), round(0.1*len(flat_fft)), dim=0, sorted=False)\n", + " top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + " top10[topk.indices] = flat_fft[topk.indices]\n", + " reverse_top10 = fft.irfft(top10)\n", + " g.grad = reverse_top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.125680 [ 0/735856]\n", + "loss: 1.490153 [64000/735856]\n", + "loss: 0.797238 [128000/735856]\n", + "loss: 0.703639 [192000/735856]\n", + "loss: 0.862654 [256000/735856]\n", + "loss: 0.674491 [320000/735856]\n", + "loss: 0.633835 [384000/735856]\n", + "loss: 0.537149 [448000/735856]\n", + "loss: 0.579062 [512000/735856]\n", + "loss: 0.468447 [576000/735856]\n", + "loss: 0.488582 [640000/735856]\n", + "loss: 0.529873 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 83.8%, Avg loss: 0.489548 \n", + "\n", + "loss: 0.573154 [ 0/735856]\n", + "loss: 0.466781 [64000/735856]\n", + "loss: 0.468422 [128000/735856]\n", + "loss: 0.449423 [192000/735856]\n", + "loss: 0.357713 [256000/735856]\n", + "loss: 0.391187 [320000/735856]\n", + "loss: 0.500866 [384000/735856]\n", + "loss: 0.368405 [448000/735856]\n", + "loss: 0.423239 [512000/735856]\n", + "loss: 0.533780 [576000/735856]\n", + "loss: 0.623185 [640000/735856]\n", + "loss: 0.380635 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.9%, Avg loss: 0.411804 \n", + "\n", + "loss: 0.485906 [ 0/735856]\n", + "loss: 0.522850 [64000/735856]\n", + "loss: 0.474864 [128000/735856]\n", + "loss: 0.453226 [192000/735856]\n", + "loss: 0.311791 [256000/735856]\n", + "loss: 0.370382 [320000/735856]\n", + "loss: 0.415271 [384000/735856]\n", + "loss: 0.448348 [448000/735856]\n", + "loss: 0.416761 [512000/735856]\n", + "loss: 0.392923 [576000/735856]\n", + "loss: 0.408733 [640000/735856]\n", + "loss: 0.369844 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.8%, Avg loss: 0.382454 \n", + "\n", + "loss: 0.351067 [ 0/735856]\n", + "loss: 0.441320 [64000/735856]\n", + "loss: 0.376012 [128000/735856]\n", + "loss: 0.326137 [192000/735856]\n", + "loss: 0.326353 [256000/735856]\n", + "loss: 0.337223 [320000/735856]\n", + "loss: 0.377199 [384000/735856]\n", + "loss: 0.453688 [448000/735856]\n", + "loss: 0.394669 [512000/735856]\n", + "loss: 0.462621 [576000/735856]\n", + "loss: 0.365274 [640000/735856]\n", + "loss: 0.414022 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.0%, Avg loss: 0.381759 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " \n", + " flat_fft = fft.rfft(flat)\n", + " topk = torch.topk(flat_fft.abs(), round(0.2*len(flat_fft)), dim=0, sorted=False)\n", + " top10 = torch.zeros(len(flat_fft), dtype = torch.cfloat)\n", + " top10[topk.indices] = flat_fft[topk.indices]\n", + " reverse_top10 = fft.irfft(top10)\n", + " g.grad = reverse_top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 229, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 230, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.128546 [ 0/735856]\n", + "loss: 1.380654 [64000/735856]\n", + "loss: 1.055664 [128000/735856]\n", + "loss: 0.687121 [192000/735856]\n", + "loss: 0.728443 [256000/735856]\n", + "loss: 0.731651 [320000/735856]\n", + "loss: 0.649674 [384000/735856]\n", + "loss: 0.474646 [448000/735856]\n", + "loss: 0.653415 [512000/735856]\n", + "loss: 0.450781 [576000/735856]\n", + "loss: 0.629819 [640000/735856]\n", + "loss: 0.548388 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 83.2%, Avg loss: 0.540368 \n", + "\n", + "loss: 0.767534 [ 0/735856]\n", + "loss: 0.474996 [64000/735856]\n", + "loss: 0.657538 [128000/735856]\n", + "loss: 0.388315 [192000/735856]\n", + "loss: 0.581206 [256000/735856]\n", + "loss: 0.421425 [320000/735856]\n", + "loss: 0.494563 [384000/735856]\n", + "loss: 0.541493 [448000/735856]\n", + "loss: 0.451657 [512000/735856]\n", + "loss: 0.382599 [576000/735856]\n", + "loss: 0.449485 [640000/735856]\n", + "loss: 0.408576 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.0%, Avg loss: 0.455863 \n", + "\n", + "loss: 0.487152 [ 0/735856]\n", + "loss: 0.566136 [64000/735856]\n", + "loss: 0.388435 [128000/735856]\n", + "loss: 0.435407 [192000/735856]\n", + "loss: 0.626423 [256000/735856]\n", + "loss: 0.436673 [320000/735856]\n", + "loss: 0.599878 [384000/735856]\n", + "loss: 0.567672 [448000/735856]\n", + "loss: 0.458641 [512000/735856]\n", + "loss: 0.479425 [576000/735856]\n", + "loss: 0.289777 [640000/735856]\n", + "loss: 0.392798 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.1%, Avg loss: 0.449504 \n", + "\n", + "loss: 0.616642 [ 0/735856]\n", + "loss: 0.266790 [64000/735856]\n", + "loss: 0.314584 [128000/735856]\n", + "loss: 0.314711 [192000/735856]\n", + "loss: 0.429452 [256000/735856]\n", + "loss: 0.363823 [320000/735856]\n", + "loss: 0.594678 [384000/735856]\n", + "loss: 0.417127 [448000/735856]\n", + "loss: 0.415177 [512000/735856]\n", + "loss: 0.406279 [576000/735856]\n", + "loss: 0.512797 [640000/735856]\n", + "loss: 0.259631 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.3%, Avg loss: 0.415515 \n", + "\n" + ] + } + ], + "source": [ + "# wavelet per layer\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'haar'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " \n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + " g.grad = reverse_top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.114821 [ 0/735856]\n", + "loss: 1.691283 [64000/735856]\n", + "loss: 0.739705 [128000/735856]\n", + "loss: 0.878835 [192000/735856]\n", + "loss: 0.893373 [256000/735856]\n", + "loss: 0.622142 [320000/735856]\n", + "loss: 0.729517 [384000/735856]\n", + "loss: 0.930510 [448000/735856]\n", + "loss: 0.564309 [512000/735856]\n", + "loss: 0.820855 [576000/735856]\n", + "loss: 0.592394 [640000/735856]\n", + "loss: 0.530982 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 82.1%, Avg loss: 0.576240 \n", + "\n", + "loss: 0.387244 [ 0/735856]\n", + "loss: 0.483110 [64000/735856]\n", + "loss: 0.544743 [128000/735856]\n", + "loss: 0.570393 [192000/735856]\n", + "loss: 0.511510 [256000/735856]\n", + "loss: 0.335736 [320000/735856]\n", + "loss: 0.671059 [384000/735856]\n", + "loss: 0.473634 [448000/735856]\n", + "loss: 0.559810 [512000/735856]\n", + "loss: 0.454633 [576000/735856]\n", + "loss: 0.571824 [640000/735856]\n", + "loss: 0.626598 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 84.3%, Avg loss: 0.482487 \n", + "\n", + "loss: 0.422876 [ 0/735856]\n", + "loss: 0.769186 [64000/735856]\n", + "loss: 0.351542 [128000/735856]\n", + "loss: 0.436626 [192000/735856]\n", + "loss: 0.628383 [256000/735856]\n", + "loss: 0.528591 [320000/735856]\n", + "loss: 0.573713 [384000/735856]\n", + "loss: 0.517758 [448000/735856]\n", + "loss: 0.434379 [512000/735856]\n", + "loss: 0.491439 [576000/735856]\n", + "loss: 0.494193 [640000/735856]\n", + "loss: 0.505279 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.1%, Avg loss: 0.454134 \n", + "\n", + "loss: 0.439892 [ 0/735856]\n", + "loss: 0.459202 [64000/735856]\n", + "loss: 0.245611 [128000/735856]\n", + "loss: 0.355409 [192000/735856]\n", + "loss: 0.490522 [256000/735856]\n", + "loss: 0.481495 [320000/735856]\n", + "loss: 0.426439 [384000/735856]\n", + "loss: 0.641797 [448000/735856]\n", + "loss: 0.423894 [512000/735856]\n", + "loss: 0.498421 [576000/735856]\n", + "loss: 0.344970 [640000/735856]\n", + "loss: 0.368346 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 84.2%, Avg loss: 0.466052 \n", + "\n" + ] + } + ], + "source": [ + "# per layer repeat\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'sym2'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " \n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " flat = g.grad.flatten()\n", + " \n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " # print(len(coeff))\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + " g.grad = reverse_top10.reshape(shape)\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.135039 [ 0/735856]\n", + "loss: 1.154176 [64000/735856]\n", + "loss: 0.624926 [128000/735856]\n", + "loss: 0.605651 [192000/735856]\n", + "loss: 0.601686 [256000/735856]\n", + "loss: 0.532184 [320000/735856]\n", + "loss: 0.627395 [384000/735856]\n", + "loss: 0.411491 [448000/735856]\n", + "loss: 0.354714 [512000/735856]\n", + "loss: 0.393673 [576000/735856]\n", + "loss: 0.612208 [640000/735856]\n", + "loss: 0.619142 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.2%, Avg loss: 0.445382 \n", + "\n", + "loss: 0.429652 [ 0/735856]\n", + "loss: 0.396769 [64000/735856]\n", + "loss: 0.423508 [128000/735856]\n", + "loss: 0.576669 [192000/735856]\n", + "loss: 0.432909 [256000/735856]\n", + "loss: 0.515018 [320000/735856]\n", + "loss: 0.375972 [384000/735856]\n", + "loss: 0.376615 [448000/735856]\n", + "loss: 0.326449 [512000/735856]\n", + "loss: 0.360019 [576000/735856]\n", + "loss: 0.354862 [640000/735856]\n", + "loss: 0.522963 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.9%, Avg loss: 0.383029 \n", + "\n", + "loss: 0.319733 [ 0/735856]\n", + "loss: 0.486813 [64000/735856]\n", + "loss: 0.351780 [128000/735856]\n", + "loss: 0.327754 [192000/735856]\n", + "loss: 0.311207 [256000/735856]\n", + "loss: 0.421759 [320000/735856]\n", + "loss: 0.486802 [384000/735856]\n", + "loss: 0.327473 [448000/735856]\n", + "loss: 0.229189 [512000/735856]\n", + "loss: 0.395156 [576000/735856]\n", + "loss: 0.330383 [640000/735856]\n", + "loss: 0.240293 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.1%, Avg loss: 0.374847 \n", + "\n", + "loss: 0.364167 [ 0/735856]\n", + "loss: 0.325380 [64000/735856]\n", + "loss: 0.407133 [128000/735856]\n", + "loss: 0.229438 [192000/735856]\n", + "loss: 0.324557 [256000/735856]\n", + "loss: 0.312494 [320000/735856]\n", + "loss: 0.250331 [384000/735856]\n", + "loss: 0.405609 [448000/735856]\n", + "loss: 0.334161 [512000/735856]\n", + "loss: 0.305596 [576000/735856]\n", + "loss: 0.396855 [640000/735856]\n", + "loss: 0.267720 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.3%, Avg loss: 0.357564 \n", + "\n" + ] + } + ], + "source": [ + "# wavelet over entire flatten gradient\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'haar'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " flats = []\n", + " shapes = []\n", + " lens = []\n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " shapes.append(shape)\n", + " flat = g.grad.flatten()\n", + " flats.append(flat)\n", + " lens.append(len(flat))\n", + " flat = torch.cat(flats)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + "\n", + " \n", + " start_index = 0 \n", + " for i, key in enumerate(model.parameters()):\n", + " end_index = start_index + lens[i]\n", + " key.grad = reverse_top10[start_index:end_index].reshape(shapes[i])\n", + " start_index = end_index\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "import pywt" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.126535 [ 0/735856]\n", + "loss: 1.238513 [64000/735856]\n", + "loss: 0.947478 [128000/735856]\n", + "loss: 0.758107 [192000/735856]\n", + "loss: 0.538468 [256000/735856]\n", + "loss: 0.726651 [320000/735856]\n", + "loss: 0.523160 [384000/735856]\n", + "loss: 0.323133 [448000/735856]\n", + "loss: 0.439029 [512000/735856]\n", + "loss: 0.406259 [576000/735856]\n", + "loss: 0.490085 [640000/735856]\n", + "loss: 0.520512 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.0%, Avg loss: 0.449423 \n", + "\n", + "loss: 0.481995 [ 0/735856]\n", + "loss: 0.485922 [64000/735856]\n", + "loss: 0.363491 [128000/735856]\n", + "loss: 0.604679 [192000/735856]\n", + "loss: 0.318160 [256000/735856]\n", + "loss: 0.321950 [320000/735856]\n", + "loss: 0.355750 [384000/735856]\n", + "loss: 0.399116 [448000/735856]\n", + "loss: 0.283532 [512000/735856]\n", + "loss: 0.527641 [576000/735856]\n", + "loss: 0.413641 [640000/735856]\n", + "loss: 0.309524 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.0%, Avg loss: 0.406266 \n", + "\n", + "loss: 0.332639 [ 0/735856]\n", + "loss: 0.438504 [64000/735856]\n", + "loss: 0.375174 [128000/735856]\n", + "loss: 0.325330 [192000/735856]\n", + "loss: 0.311181 [256000/735856]\n", + "loss: 0.439757 [320000/735856]\n", + "loss: 0.357552 [384000/735856]\n", + "loss: 0.318609 [448000/735856]\n", + "loss: 0.265860 [512000/735856]\n", + "loss: 0.534769 [576000/735856]\n", + "loss: 0.287946 [640000/735856]\n", + "loss: 0.381077 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.0%, Avg loss: 0.377133 \n", + "\n", + "loss: 0.293545 [ 0/735856]\n", + "loss: 0.346547 [64000/735856]\n", + "loss: 0.489387 [128000/735856]\n", + "loss: 0.438751 [192000/735856]\n", + "loss: 0.376747 [256000/735856]\n", + "loss: 0.427431 [320000/735856]\n", + "loss: 0.381158 [384000/735856]\n", + "loss: 0.482535 [448000/735856]\n", + "loss: 0.229551 [512000/735856]\n", + "loss: 0.455859 [576000/735856]\n", + "loss: 0.332654 [640000/735856]\n", + "loss: 0.496725 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.5%, Avg loss: 0.358163 \n", + "\n" + ] + } + ], + "source": [ + "# rerun with alpha 0.2\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'sym2'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " flats = []\n", + " shapes = []\n", + " lens = []\n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " shapes.append(shape)\n", + " flat = g.grad.flatten()\n", + " flats.append(flat)\n", + " lens.append(len(flat))\n", + " flat = torch.cat(flats)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = None)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + "\n", + " \n", + " start_index = 0 \n", + " for i, key in enumerate(model.parameters()):\n", + " end_index = start_index + lens[i]\n", + " key.grad = reverse_top10[start_index:end_index].reshape(shapes[i])\n", + " start_index = end_index\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "v,i = torch.topk(torch.tensor([1,2,3,4]), 2 , dim=0, sorted=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([4, 3])" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([3, 2])" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "i" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.126898 [ 0/735856]\n", + "loss: 1.050626 [64000/735856]\n", + "loss: 0.652647 [128000/735856]\n", + "loss: 0.648297 [192000/735856]\n", + "loss: 0.636182 [256000/735856]\n", + "loss: 0.570731 [320000/735856]\n", + "loss: 0.509262 [384000/735856]\n", + "loss: 0.309913 [448000/735856]\n", + "loss: 0.538662 [512000/735856]\n", + "loss: 0.530801 [576000/735856]\n", + "loss: 0.507737 [640000/735856]\n", + "loss: 0.422813 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 85.5%, Avg loss: 0.435624 \n", + "\n", + "loss: 0.388328 [ 0/735856]\n", + "loss: 0.299637 [64000/735856]\n", + "loss: 0.420440 [128000/735856]\n", + "loss: 0.230143 [192000/735856]\n", + "loss: 0.374027 [256000/735856]\n", + "loss: 0.279048 [320000/735856]\n", + "loss: 0.495672 [384000/735856]\n", + "loss: 0.277394 [448000/735856]\n", + "loss: 0.395940 [512000/735856]\n", + "loss: 0.476103 [576000/735856]\n", + "loss: 0.550471 [640000/735856]\n", + "loss: 0.431940 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.7%, Avg loss: 0.391393 \n", + "\n", + "loss: 0.436391 [ 0/735856]\n", + "loss: 0.351771 [64000/735856]\n", + "loss: 0.352133 [128000/735856]\n", + "loss: 0.254270 [192000/735856]\n", + "loss: 0.357840 [256000/735856]\n", + "loss: 0.368416 [320000/735856]\n", + "loss: 0.401375 [384000/735856]\n", + "loss: 0.442322 [448000/735856]\n", + "loss: 0.538914 [512000/735856]\n", + "loss: 0.444955 [576000/735856]\n", + "loss: 0.322195 [640000/735856]\n", + "loss: 0.493332 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.9%, Avg loss: 0.374818 \n", + "\n", + "loss: 0.457855 [ 0/735856]\n", + "loss: 0.423867 [64000/735856]\n", + "loss: 0.274726 [128000/735856]\n", + "loss: 0.356364 [192000/735856]\n", + "loss: 0.341427 [256000/735856]\n", + "loss: 0.301665 [320000/735856]\n", + "loss: 0.409492 [384000/735856]\n", + "loss: 0.401218 [448000/735856]\n", + "loss: 0.616257 [512000/735856]\n", + "loss: 0.287706 [576000/735856]\n", + "loss: 0.321826 [640000/735856]\n", + "loss: 0.423405 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.6%, Avg loss: 0.357925 \n", + "\n" + ] + } + ], + "source": [ + "# rerun with alpha 0.2 and level 4\n", + "stats = {\"train\": [], \"test\":[]}\n", + "wavelet = 'coif1'\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " flats = []\n", + " shapes = []\n", + " lens = []\n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " shapes.append(shape)\n", + " flat = g.grad.flatten()\n", + " flats.append(flat)\n", + " lens.append(len(flat))\n", + " flat = torch.cat(flats)\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " # print(len(coeff))\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.2*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " \n", + "\n", + " \n", + " start_index = 0 \n", + " for i, key in enumerate(model.parameters()):\n", + " end_index = start_index + lens[i]\n", + " key.grad = reverse_top10[start_index:end_index].reshape(shapes[i])\n", + " start_index = end_index\n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.0005\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.118358 [ 0/735856]\n", + "loss: 1.330925 [64000/735856]\n", + "loss: 0.899926 [128000/735856]\n", + "loss: 0.894990 [192000/735856]\n", + "loss: 0.475845 [256000/735856]\n", + "loss: 0.672299 [320000/735856]\n", + "loss: 0.728748 [384000/735856]\n", + "loss: 0.374176 [448000/735856]\n", + "loss: 0.621309 [512000/735856]\n", + "loss: 0.562943 [576000/735856]\n", + "loss: 0.567177 [640000/735856]\n", + "loss: 0.408742 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 84.7%, Avg loss: 0.461047 \n", + "\n", + "loss: 0.545014 [ 0/735856]\n", + "loss: 0.433877 [64000/735856]\n", + "loss: 0.513009 [128000/735856]\n", + "loss: 0.462199 [192000/735856]\n", + "loss: 0.371584 [256000/735856]\n", + "loss: 0.380919 [320000/735856]\n", + "loss: 0.448126 [384000/735856]\n", + "loss: 0.421078 [448000/735856]\n", + "loss: 0.531703 [512000/735856]\n", + "loss: 0.314307 [576000/735856]\n", + "loss: 0.345081 [640000/735856]\n", + "loss: 0.456303 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.6%, Avg loss: 0.392272 \n", + "\n", + "loss: 0.371980 [ 0/735856]\n", + "loss: 0.419902 [64000/735856]\n", + "loss: 0.344231 [128000/735856]\n", + "loss: 0.383977 [192000/735856]\n", + "loss: 0.586718 [256000/735856]\n", + "loss: 0.524982 [320000/735856]\n", + "loss: 0.333949 [384000/735856]\n", + "loss: 0.478536 [448000/735856]\n", + "loss: 0.346808 [512000/735856]\n", + "loss: 0.322247 [576000/735856]\n", + "loss: 0.281340 [640000/735856]\n", + "loss: 0.373933 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 86.8%, Avg loss: 0.379021 \n", + "\n", + "loss: 0.393135 [ 0/735856]\n", + "loss: 0.281718 [64000/735856]\n", + "loss: 0.488630 [128000/735856]\n", + "loss: 0.335369 [192000/735856]\n", + "loss: 0.342869 [256000/735856]\n", + "loss: 0.293455 [320000/735856]\n", + "loss: 0.391644 [384000/735856]\n", + "loss: 0.309957 [448000/735856]\n", + "loss: 0.277645 [512000/735856]\n", + "loss: 0.277113 [576000/735856]\n", + "loss: 0.242315 [640000/735856]\n", + "loss: 0.292711 [704000/735856]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 87.3%, Avg loss: 0.366945 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(4):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " # print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " \n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " # print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " \n", + " \n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " # print(\"params \"+ str(len(list(model.parameters()))))\n", + " flats = []\n", + " shapes = []\n", + " lens = []\n", + " for g in model.parameters():\n", + " grad = g.grad\n", + " shape = grad.shape\n", + " shapes.append(shape)\n", + " flat = g.grad.flatten()\n", + " flats.append(flat)\n", + " lens.append(len(flat))\n", + " flat = torch.cat(flats)\n", + "\n", + " topk = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat))\n", + " top10[topk.indices] = flat[topk.indices]\n", + " \n", + " start_index = 0 \n", + " for i, key in enumerate(model.parameters()):\n", + " end_index = start_index + lens[i]\n", + " key.grad = top10[start_index:end_index].reshape(shapes[i])\n", + " start_index = end_index\n", + " \n", + " \n", + " # print(\"grad3: \"+str(model.conv1.bias.grad))\n", + " \n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " # print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Node Training <a class=\"anchor\" id=\"nodetraining\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "9LpgzEw1s-xo" + }, + "outputs": [], + "source": [ + "# From Femnist.py\n", + "def read_file(file_path):\n", + " with open(file_path, \"r\") as inf:\n", + " client_data = json.load(inf)\n", + " print(\"loaded the data\")\n", + " return (\n", + " client_data[\"users\"],\n", + " client_data[\"num_samples\"],\n", + " client_data[\"user_data\"],\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QBu1kiw8s-xr" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "raw", + "metadata": { + "id": "jI3ixEN4s-xt", + "outputId": "ed969663-9e1e-4810-9507-52cdc426650a" + }, + "source": [ + "# From Femnist.py\n", + "for i in range(1):\n", + " cur_file = \"leaf/data/femnist/data/train/all_data_0_niid_0_keep_0_train_9.json\"\n", + " # test_file = \"leaf/data/femnist/data/test/all_data_0_niid_0_keep_0_test_9.json\"\n", + " # cur_file = test_file\n", + " clients, _, train_data = read_file(\n", + " os.path.join(train_dir, cur_file)\n", + " )\n", + " for cur_client in clients:\n", + " # self.clients.append(cur_client)\n", + " my_train_data[\"x\"].extend(train_data[cur_client][\"x\"])\n", + " my_train_data[\"y\"].extend(train_data[cur_client][\"y\"])\n", + " del train_data[cur_client]\n" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "wvHsSz8as-xw" + }, + "source": [ + "train_x = (\n", + " np.array(my_train_data[\"x\"], dtype=np.dtype(\"float32\"))\n", + " .reshape(-1, 28, 28, 1)\n", + " .transpose(0, 3, 1, 2)\n", + ")\n", + "train_y = np.array(my_train_data[\"y\"], dtype=np.dtype(\"int64\")).reshape(-1)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "K8X471SKs-xz", + "outputId": "cdf73c06-1323-4e76-850b-16324008d255" + }, + "source": [ + "len(train_y)" + ] + }, + { + "cell_type": "raw", + "metadata": { + "id": "EpWNELBrs-x0" + }, + "source": [ + "with open(train_dir+\"femnist.pkl\", \"wb\") as f:\n", + " pickle.dump({\"test_x\": train_x, \"test_y\": train_y}, f)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "mAEASHr2s-x1" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "7665.166666666667" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "735856 / 96\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "Am_XlcSSs-x3" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "evAd9ZvYs-x6" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "9_vIFakbs-x7", + "outputId": "3a8b546a-186f-4519-8c0b-e853986a8101" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856, 1, 28, 28)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_x\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "GPyZ2C8ws-x9" + }, + "outputs": [], + "source": [ + "NUM_CLASSES = 62\n", + "IMAGE_SIZE = (28, 28)\n", + "FLAT_SIZE = 28 * 28\n", + "PIXEL_RANGE = 256.0\n", + "import torch.nn.functional as F\n", + "\n", + "class CNN(nn.Module):\n", + " \"\"\"\n", + " Class for a CNN Model for FEMNIST\n", + "\n", + " \"\"\"\n", + "\n", + " def __init__(self):\n", + " \"\"\"\n", + " Constructor. Instantiates the CNN Model\n", + " with 28*28*1 Input and 62 output classes\n", + "\n", + " \"\"\"\n", + " super().__init__()\n", + " # 1.6 million params\n", + " self.conv1 = nn.Conv2d(1, 32, 5, padding=2)\n", + " self.pool = nn.MaxPool2d(2, 2)\n", + " self.conv2 = nn.Conv2d(32, 64, 5, padding=2)\n", + " self.fc1 = nn.Linear(7 * 7 * 64, 512)\n", + " self.fc2 = nn.Linear(512, NUM_CLASSES)\n", + "\n", + " def forward(self, x):\n", + " \"\"\"\n", + " Forward pass of the model\n", + "\n", + " Parameters\n", + " ----------\n", + " x : torch.tensor\n", + " The input torch tensor\n", + "\n", + " Returns\n", + " -------\n", + " torch.tensor\n", + " The output torch tensor\n", + "\n", + " \"\"\"\n", + " x = self.pool(F.relu(self.conv1(x)))\n", + " x = self.pool(F.relu(self.conv2(x)))\n", + " x = torch.flatten(x, 1)\n", + " x = F.relu(self.fc1(x))\n", + " x = self.fc2(x)\n", + " return x\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "bCgW8ClBs-x_" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(735856,)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train[\"train_y\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "id": "oBGwcwZks-yA" + }, + "outputs": [], + "source": [ + "import os\n", + "from torch.utils.data import Dataset\n", + "\n", + "class FemnistDataset(Dataset):\n", + " def __init__(self, training, transform=None, target_transform=None):\n", + " if training:\n", + " with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " train = pickle.load(f)\n", + " self.data = train[\"train_x\"][10000:10000+7665,...]\n", + " self.label = train[\"train_y\"][10000:10000+7665,...]\n", + " else: \n", + " with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " test = pickle.load(f)\n", + " self.data = test[\"test_x\"]\n", + " self.label = test[\"test_y\"]\n", + " self.transform = transform\n", + " self.target_transform = target_transform\n", + "\n", + " def __len__(self):\n", + " return len(self.label)\n", + "\n", + " def __getitem__(self, idx):\n", + " return self.data[idx], self.label[idx]" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "U3boC_N4s-yC" + }, + "outputs": [], + "source": [ + "from torch.utils.data import DataLoader" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "sJsrQXkEs-yD" + }, + "outputs": [], + "source": [ + "trainset = FemnistDataset(True)\n", + "testset = FemnistDataset(False)\n", + "\n", + "train_dataloader = DataLoader(trainset, batch_size=16, shuffle=True)\n", + "test_dataloader = DataLoader(testset, batch_size=128, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "480" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(train_dataloader)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "id": "e65Izyv0s-yE" + }, + "outputs": [], + "source": [ + "lr = 0.001\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1487, -0.1003, 0.0990, -0.0245, -0.1023, 0.0974, -0.1139, -0.1425,\n", + " -0.1949, -0.0679, -0.0937, 0.0891, 0.0577, -0.1357, 0.0814, 0.1157,\n", + " -0.1997, -0.1665, -0.1546, 0.1150, 0.0895, -0.1049, -0.0980, -0.0980,\n", + " 0.0729, 0.1947, 0.0421, -0.0365, -0.1470, -0.1679, 0.0286, -0.0146])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "tensor([-0.0180, 0.0236, 0.1279, -0.1352, -0.1948, -0.0330, -0.1615, -0.0286,\n", + " -0.1762, 0.0040, 0.1570, -0.1069, -0.1074, -0.1417, -0.1171, 0.0359,\n", + " 0.1276, -0.1534, -0.1773, -0.1639, 0.1334, 0.0518, 0.0586, 0.1466,\n", + " 0.1283, 0.0443, -0.0982, -0.1739, -0.0061, 0.1047, -0.0291, 0.1525])" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "for p in model.parameters():\n", + " print(p.data.size())\n", + " p.data = torch.zeros(p.data.size())" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.1487, -0.1003, 0.0990, -0.0245, -0.1023, 0.0974, -0.1139, -0.1425,\n", + " -0.1949, -0.0679, -0.0937, 0.0891, 0.0577, -0.1357, 0.0814, 0.1157,\n", + " -0.1997, -0.1665, -0.1546, 0.1150, 0.0895, -0.1049, -0.0980, -0.0980,\n", + " 0.0729, 0.1947, 0.0421, -0.0365, -0.1470, -0.1679, 0.0286, -0.0146])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(model.state_dict().values())[1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "eqOXilqMs-yF", + "outputId": "06799a3b-983b-4f51-a7bd-a901c041bd05" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.158939 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 34.5%, Avg loss: 2.492351 \n", + "\n", + "loss: 2.274407 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 49.2%, Avg loss: 2.004063 \n", + "\n", + "loss: 2.080229 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 57.7%, Avg loss: 1.550052 \n", + "\n", + "loss: 1.220055 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 62.5%, Avg loss: 1.387109 \n", + "\n", + "loss: 0.547404 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 62.6%, Avg loss: 1.411219 \n", + "\n", + "loss: 0.666172 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 68.1%, Avg loss: 1.147880 \n", + "\n", + "loss: 0.539106 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 66.9%, Avg loss: 1.218418 \n", + "\n", + "loss: 1.057546 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 68.9%, Avg loss: 1.211012 \n", + "\n", + "loss: 0.315841 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 66.5%, Avg loss: 1.400047 \n", + "\n", + "loss: 0.659244 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 66.0%, Avg loss: 1.484381 \n", + "\n", + "loss: 0.437452 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 69.8%, Avg loss: 1.239514 \n", + "\n", + "loss: 0.675393 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 69.3%, Avg loss: 1.224045 \n", + "\n", + "loss: 0.409850 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 67.5%, Avg loss: 1.499410 \n", + "\n", + "loss: 0.942130 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 69.7%, Avg loss: 1.331600 \n", + "\n", + "loss: 0.193678 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 69.5%, Avg loss: 1.398448 \n", + "\n", + "loss: 0.120872 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 68.4%, Avg loss: 1.589930 \n", + "\n", + "loss: 0.099591 [ 0/ 7665]\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(20):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " #print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " #print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " #print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "lr = 0.001\n", + "model = CNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=0.001)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.158939 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 26.3%, Avg loss: 2.828093 \n", + "\n", + "loss: 2.478634 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 47.1%, Avg loss: 2.069258 \n", + "\n", + "loss: 2.099130 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 56.7%, Avg loss: 1.571264 \n", + "\n", + "loss: 1.343866 [ 0/ 7665]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 61.1%, Avg loss: 1.432287 \n", + "\n", + "loss: 0.783433 [ 0/ 7665]\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [18]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 48\u001b[0m X \u001b[38;5;241m=\u001b[39m X\u001b[38;5;241m.\u001b[39mto(device)\n\u001b[1;32m 49\u001b[0m y \u001b[38;5;241m=\u001b[39m y\u001b[38;5;241m.\u001b[39mto(device)\n\u001b[0;32m---> 50\u001b[0m pred \u001b[38;5;241m=\u001b[39m \u001b[43mmodel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mX\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 51\u001b[0m test_loss \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m loss_fn(pred, y)\u001b[38;5;241m.\u001b[39mitem()\n\u001b[1;32m 52\u001b[0m correct \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m (pred\u001b[38;5;241m.\u001b[39margmax(\u001b[38;5;241m1\u001b[39m) \u001b[38;5;241m==\u001b[39m y)\u001b[38;5;241m.\u001b[39mtype(torch\u001b[38;5;241m.\u001b[39mfloat)\u001b[38;5;241m.\u001b[39msum()\u001b[38;5;241m.\u001b[39mitem()\n", + "File \u001b[0;32m~/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/nn/modules/module.py:1102\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 1098\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m 1099\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m 1100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m 1101\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1102\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mforward_call\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1103\u001b[0m \u001b[38;5;66;03m# Do not call functions when jit is used\u001b[39;00m\n\u001b[1;32m 1104\u001b[0m full_backward_hooks, non_full_backward_hooks \u001b[38;5;241m=\u001b[39m [], []\n", + "Input \u001b[0;32mIn [11]\u001b[0m, in \u001b[0;36mCNN.forward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;124;03mForward pass of the model\u001b[39;00m\n\u001b[1;32m 30\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 40\u001b[0m \n\u001b[1;32m 41\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 42\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpool(F\u001b[38;5;241m.\u001b[39mrelu(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconv1(x)))\n\u001b[0;32m---> 43\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpool(F\u001b[38;5;241m.\u001b[39mrelu(\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconv2\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m))\n\u001b[1;32m 44\u001b[0m x \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mflatten(x, \u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m 45\u001b[0m x \u001b[38;5;241m=\u001b[39m F\u001b[38;5;241m.\u001b[39mrelu(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfc1(x))\n", + "File \u001b[0;32m~/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/nn/modules/module.py:1102\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 1098\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m 1099\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m 1100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m 1101\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1102\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mforward_call\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1103\u001b[0m \u001b[38;5;66;03m# Do not call functions when jit is used\u001b[39;00m\n\u001b[1;32m 1104\u001b[0m full_backward_hooks, non_full_backward_hooks \u001b[38;5;241m=\u001b[39m [], []\n", + "File \u001b[0;32m~/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/nn/modules/conv.py:446\u001b[0m, in \u001b[0;36mConv2d.forward\u001b[0;34m(self, input)\u001b[0m\n\u001b[1;32m 445\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mforward\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;28minput\u001b[39m: Tensor) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Tensor:\n\u001b[0;32m--> 446\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_conv_forward\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mweight\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbias\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/nn/modules/conv.py:442\u001b[0m, in \u001b[0;36mConv2d._conv_forward\u001b[0;34m(self, input, weight, bias)\u001b[0m\n\u001b[1;32m 438\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpadding_mode \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mzeros\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 439\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m F\u001b[38;5;241m.\u001b[39mconv2d(F\u001b[38;5;241m.\u001b[39mpad(\u001b[38;5;28minput\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reversed_padding_repeated_twice, mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpadding_mode),\n\u001b[1;32m 440\u001b[0m weight, bias, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstride,\n\u001b[1;32m 441\u001b[0m _pair(\u001b[38;5;241m0\u001b[39m), \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdilation, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgroups)\n\u001b[0;32m--> 442\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mF\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconv2d\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mweight\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbias\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstride\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 443\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpadding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdilation\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgroups\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "for e in range(20):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " #print(\"grad: \"+str(model.conv1.bias.grad))\n", + " old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + " # https://stackoverflow.com/questions/42704283/adding-l1-l2-regularization-in-pytorch\n", + " #to_cat = []\n", + " #for v in model.state_dict.values():\n", + " # flat = v.flatten()\n", + " # to_cat.append(flat)\n", + " #flat = torch.cat(to_cat, dim=0)\n", + " #loss = loss_fn(pred,y) + 0.02*torch.norm(flat, 2)\n", + " # Backpropagation\n", + " loss.backward()\n", + " #print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " optimizer.step()\n", + " optimizer.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " #print(optimizer.state.values())\n", + "\n", + " if batch % 500 == 0:\n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + " batch += 1\n", + " \n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "after 8: Accuracy: 67.3%, Avg loss: 1.200284 " + ] + } + ], + "metadata": { + "colab": { + "name": "learningrate.ipynb", + "provenance": [] + }, + "interpreter": { + "hash": "996934296aa9d79be6c3d800a38d8fdb7dfa8fe7bb07df178f1397cde2cb8742" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/random files/multiprocessing_tests.py b/random files/multiprocessing_tests.py new file mode 100644 index 0000000000000000000000000000000000000000..59b00ba2276489160924366d749cf15ddb3e5d02 --- /dev/null +++ b/random files/multiprocessing_tests.py @@ -0,0 +1,56 @@ +import multiprocessing as omp +import time +from ctypes import c_int + +# from multiprocessing.queues import Queue +from multiprocessing.sharedctypes import Value + +import torch.multiprocessing as mp + + +def do_something_out(rank, node, queue, shared): # first argument is rank + print(f"run {rank}") + print(type(queue)) + node.queue.put("do_something_out") + print(f"run {rank}") + node.val = 2 + shared.value = 2 + print("run") + + +class Node: + def __init__(self, queue): + super(Node, self).__init__() + self.queue = queue + self.val = 1 + # mp.spawn(Node.do_something) + # start_processes + # do_something_out(self) + self.x = Value(c_int, 1, lock=False) + print(type(self.x)) + print("actual value:", self.x.value) + mp.start_processes( + do_something_out, args=(self, self.queue, self.x), start_method="fork" + ) + + def do_something(self): + # t.queue.put("do_something") + print("do_something") + self.val = 2 + + +if __name__ == "__main__": + queue = mp.Queue() + # queue.put("test") + node = Node(queue) + # mp.start_processes( + # do_something_out, + # (node, queue,), + # start_method="fork" + # ) + + time.sleep(3) + print(node.queue.get()) + print(node.val) + print(node.x.value) + # print(node.val) diff --git a/random files/playground_jw.ipynb b/random files/playground_jw.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..118dd638637b66c877d5927c5e4a9691116d86de --- /dev/null +++ b/random files/playground_jw.ipynb @@ -0,0 +1,999 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from decentralizepy.datasets.Femnist import Femnist\n", + "from decentralizepy.graphs import SmallWorld\n", + "from collections import defaultdict\n", + "import os\n", + "import json\n", + "import numpy as np\n", + "import torch " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1256779281901044017" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "random_generator = torch.Generator()\n", + "# Will use the random device if supported by CPU, else uses the system time\n", + "# In the latter case we could get duplicate seeds on some of the machines\n", + "random_generator.seed()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "seed = random_generator.initial_seed()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.7203, 0.5044, 0.1496, 0.6218, 0.5369, 0.8994, 0.9816, 0.9307, 0.7464,\n", + " 0.8109, 0.0372, 0.5295, 0.1905, 0.1923, 0.6036, 0.0288, 0.1395, 0.8307,\n", + " 0.0180, 0.8481])" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.rand(20, generator = random_generator)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.2485, 0.6399, 0.7028, 0.0918, 0.3800, 0.3301, 0.4674, 0.1821, 0.0140,\n", + " 0.5983, 0.4028, 0.2738, 0.5664, 0.1826, 0.8313, 0.8182, 0.8255, 0.4354,\n", + " 0.2829, 0.1707])" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.rand(20, generator = random_generator)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<torch._C.Generator at 0x7f415f3a9790>" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "random_generator2 = torch.Generator()\n", + "random_generator2.manual_seed(seed)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.7203, 0.5044, 0.1496, 0.6218, 0.5369, 0.8994, 0.9816, 0.9307, 0.7464,\n", + " 0.8109, 0.0372, 0.5295, 0.1905, 0.1923, 0.6036, 0.0288, 0.1395, 0.8307,\n", + " 0.0180, 0.8481])" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.rand(20, generator = random_generator2)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.2485, 0.6399, 0.7028, 0.0918, 0.3800, 0.3301, 0.4674, 0.1821, 0.0140,\n", + " 0.5983, 0.4028, 0.2738, 0.5664, 0.1826, 0.8313, 0.8182, 0.8255, 0.4354,\n", + " 0.2829, 0.1707])" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.rand(20, generator = random_generator2)" + ] + }, + { + "cell_type": "code", + "execution_count": 133, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0],\n", + " dtype=torch.int32)" + ] + }, + "execution_count": 133, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Or we could use torch.bernoulli\n", + "alpha = 0.3\n", + "(torch.rand(size=(20,), generator = random_generator) < alpha).int()" + ] + }, + { + "cell_type": "code", + "execution_count": 134, + "metadata": {}, + "outputs": [], + "source": [ + "concated = torch.abs(torch.cat([torch.ones(10), torch.ones(5)*2], dim=0))" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2.])" + ] + }, + "execution_count": 135, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "concated" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "15" + ] + }, + "execution_count": 136, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "concated.size(dim = 0)" + ] + }, + { + "cell_type": "code", + "execution_count": 137, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1], dtype=torch.int32)" + ] + }, + "execution_count": 137, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "binary_mask = (torch.rand(size=(concated.size(dim = 0),), generator=random_generator) < alpha).int()\n", + "binary_mask" + ] + }, + { + "cell_type": "code", + "execution_count": 138, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ True, True, False, False, False, False, True, False, False, False,\n", + " False, True, True, False, True])" + ] + }, + "execution_count": 138, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "binary_mask = (torch.rand(size=(concated.size(dim = 0),), generator=random_generator) < alpha)\n", + "binary_mask" + ] + }, + { + "cell_type": "code", + "execution_count": 139, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([1., 1., 1., 2., 2., 2.])" + ] + }, + "execution_count": 139, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "subsample = concated[binary_mask] # torch.masked_select\n", + "subsample" + ] + }, + { + "cell_type": "code", + "execution_count": 145, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 145, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "subsample.size(dim = 0)" + ] + }, + { + "cell_type": "code", + "execution_count": 148, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])" + ] + }, + "execution_count": 148, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ground = torch.zeros(size = (15, ))\n", + "ground" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ True, True, False, False, False, False, True, False, False, False,\n", + " False, True, True, False, True])" + ] + }, + "execution_count": 143, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "binary_mask" + ] + }, + { + "cell_type": "code", + "execution_count": 149, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0., 0., 0., 0., 0., 0.])" + ] + }, + "execution_count": 149, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ground[binary_mask]" + ] + }, + { + "cell_type": "code", + "execution_count": 150, + "metadata": {}, + "outputs": [], + "source": [ + "ground[binary_mask] = subsample" + ] + }, + { + "cell_type": "code", + "execution_count": 151, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([1., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 2., 2., 0., 2.])" + ] + }, + "execution_count": 151, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ground" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing Serialization Speeds" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import pickle\n", + "import time \n", + "import json\n", + "import ujson\n", + "import torch\n", + "import orjson\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.009081792831420899\n" + ] + } + ], + "source": [ + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " bin = pickle.dumps(test)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.0366546154022216\n" + ] + } + ], + "source": [ + "#single json encoding\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " test_list = test.numpy().tolist()\n", + " binary = json.dumps(test_list)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "str" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(binary)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.500225853919983\n" + ] + } + ], + "source": [ + "# double json encoding\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " test_list = test.numpy().tolist()\n", + " jsondata = json.dumps(test_list)\n", + " m = dict()\n", + " m[\"asjson\"] = jsondata\n", + " finaljson = json.dumps(m)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.7114214897155762\n" + ] + } + ], + "source": [ + "#single ujson encoding: with to list\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " test_list = test.numpy().tolist()\n", + " binary = ujson.dumps(test_list)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "array([0.9719833 , 0.19759083, 0.06048423, ..., 0.10139698, 0.10623038,\n 0.16747206], dtype=float32) is not JSON serializable", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [14]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m t1 \u001b[38;5;241m=\u001b[39m time\u001b[38;5;241m.\u001b[39mtime()\n\u001b[1;32m 6\u001b[0m test_list \u001b[38;5;241m=\u001b[39m test\u001b[38;5;241m.\u001b[39mnumpy()\u001b[38;5;66;03m#.tolist()\u001b[39;00m\n\u001b[0;32m----> 7\u001b[0m binary \u001b[38;5;241m=\u001b[39m \u001b[43mujson\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdumps\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtest_list\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 8\u001b[0m times\u001b[38;5;241m.\u001b[39mappend(time\u001b[38;5;241m.\u001b[39mtime() \u001b[38;5;241m-\u001b[39m t1)\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28mprint\u001b[39m(np\u001b[38;5;241m.\u001b[39mmean(times))\n", + "\u001b[0;31mTypeError\u001b[0m: array([0.9719833 , 0.19759083, 0.06048423, ..., 0.10139698, 0.10623038,\n 0.16747206], dtype=float32) is not JSON serializable" + ] + } + ], + "source": [ + "#single ujson encoding\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " test_list = test.numpy()#.tolist()\n", + " binary = ujson.dumps(test_list)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.31579806804656985\n" + ] + } + ], + "source": [ + "#single orjson encoding: with to list\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " test_list = test.numpy().tolist()\n", + " binary = orjson.dumps(test_list)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.3235017776489258\n" + ] + } + ], + "source": [ + "#single orjson encoding: with to list\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " test_list = test.numpy().tolist()\n", + " binary = orjson.dumps(test_list)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "bytes" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(binary)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.16293561458587646\n" + ] + } + ], + "source": [ + "#single orjson encoding\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " test_list = test.numpy()\n", + " binary = orjson.dumps(test_list, option = orjson.OPT_SERIALIZE_NUMPY)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.40661447048187255\n" + ] + } + ], + "source": [ + "# testing decode\n", + "#single orjson encoding: with to list\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " test_list = test.numpy()\n", + " binary = orjson.dumps(test_list, option = orjson.OPT_SERIALIZE_NUMPY)\n", + " decoded = orjson.loads(binary)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "list" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(decoded)" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "#single orjson encoding: with pickle\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " binary = pickle.dumps(test)\n", + " dictionary = {}\n", + " dictionary[\"array\"] = binary\n", + " json_binary = orjson.dumps(dictionary, option = orjson.OPT_SERIALIZE_NUMPY)\n", + " #decoded = orjson.loads(json_binary)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))\n", + "# TypeError: Type is not JSON serializable: bytes" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " binary = pickle.dumps(test)\n", + " m = dict()\n", + " m[\"seed\"] = 10\n", + " m[\"data\"] = binary\n", + " jsondump = json.dumps(m)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))\n", + "TypeError: Object of type bytes is not JSON serializable" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " binary = pickle.dumps(test)\n", + " m = dict()\n", + " m[\"seed\"] = 10\n", + " m[\"data\"] = binary.decode('utf-8')\n", + " jsondump = json.dumps(m)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))\n", + "# UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "import base64" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.09808683395385742\n" + ] + } + ], + "source": [ + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " binary = pickle.dumps(test)\n", + " m = dict()\n", + " m[\"seed\"] = 10\n", + " m[\"data\"] = base64.b64encode(binary).decode('utf-8')\n", + " jsondump = json.dumps(m)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'gASVTAAAAAAAAACMDHRvcmNoLl91dGlsc5SMEl9yZWJ1aWxkX3RlbnNvcl92MpSTlCiMDXRvcmNoLnN0b3JhZ2WUjBBfbG9hZF9m'" + ] + }, + "execution_count": 120, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m[\"data\"][0:100]" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.0484, 0.4790, 0.4148, 0.8002, 0.2449, 0.2223, 0.4366, 0.7714, 0.8805,\n", + " 0.7945, 0.6266, 0.1414, 0.1102, 0.9152, 0.3609, 0.0438, 0.1110, 0.9004,\n", + " 0.8536, 0.9587])" + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test[0:20]" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [], + "source": [ + "seed = m[\"seed\"]\n", + "\n", + "params = m[\"data\"]\n", + "\n", + "\n", + "binary = base64.b64decode(params)\n", + "params = pickle.loads(binary)" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.0484, 0.4790, 0.4148, 0.8002, 0.2449, 0.2223, 0.4366, 0.7714, 0.8805,\n", + " 0.7945, 0.6266, 0.1414, 0.1102, 0.9152, 0.3609, 0.0438, 0.1110, 0.9004,\n", + " 0.8536, 0.9587])" + ] + }, + "execution_count": 123, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params[0:20]" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.05851750373840332\n" + ] + } + ], + "source": [ + "# with orjson\n", + "times = []\n", + "for i in range(10):\n", + " test = torch.rand(size = (5000000,))\n", + " t1 = time.time()\n", + " binary = pickle.dumps(test)\n", + " m = dict()\n", + " m[\"seed\"] = 10\n", + " m[\"data\"] = base64.b64encode(binary).decode('utf-8')\n", + " jsondump = orjson.dumps(m)\n", + " times.append(time.time() - t1)\n", + "print(np.mean(times))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code Snipets from Testing" + ] + }, + { + "cell_type": "code", + "execution_count": 159, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n", + " [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])" + ] + }, + "execution_count": 159, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.arange(0,20,1).reshape([2,10])" + ] + }, + { + "cell_type": "code", + "execution_count": 160, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,\n", + " 18, 19])" + ] + }, + "execution_count": 160, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.arange(0,20,1).reshape([2,10]).flatten()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "996934296aa9d79be6c3d800a38d8fdb7dfa8fe7bb07df178f1397cde2cb8742" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/random files/playground_jw_quant.ipynb b/random files/playground_jw_quant.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..bcdd39d09e3fd931e7a1ce9283b12850d48e4808 --- /dev/null +++ b/random files/playground_jw_quant.ipynb @@ -0,0 +1,4179 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from qtorch.quant import fixed_point_quantize, block_quantize, float_quantize" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from qtorch import FloatingPoint" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import pickle" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import fpzip\n", + "from pyzfp import compress, decompress\n", + "import torch\n", + "import matplotlib.pyplot as plt\n", + "from torch.quantization.observer import MinMaxObserver, MovingAverageMinMaxObserver, HistogramObserver\n", + "from torch.nn.quantized.modules.utils import _quantize_weight\n", + "import pywt" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "from decentralizepy.compression.Elias8bitQuant import Elias8bitQuant\n", + "ebit8q = Elias8bitQuant()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "a = np.random.normal(0, 0.1, 10000).astype(np.float32)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "40000" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(a)*4" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "b = fpzip.compress(a , precision=12, order='C')" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "12087" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(b)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "c = fpzip.decompress(b, order='C')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.01464844, -0.0859375 , -0.00268555, 0.01953125, 0.00317383,\n", + " -0.078125 , -0.109375 , 0.00585938, -0.1875 , -0.01464844],\n", + " dtype=float32)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "c[0][0][0][0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.50458467" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.linalg.norm((a-c)[0][0], 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.01551323, -0.08976793, -0.00279709, ..., 0.0934156 ,\n", + " -0.00322201, -0.16196491], dtype=float32)" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "at = torch.from_numpy(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "stochastic_rounded = float_quantize(at, exp=3, man=5, rounding=\"stochastic\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "7.9375" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "float_quantize(torch.tensor(np.array([10]), dtype = torch.float32), exp=2, man=6, rounding=\"nearest\").item()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# something is off this should be half the size\n", + "# it is correct 2 bits can represent 0,1,2,3\n", + "# 3 - 1 = 2\n", + "# and 2^2 is 4\n", + "# They do no do subnormal numbers" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0078125" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fixed_point_quantize(torch.tensor(np.array([0.01]), dtype = torch.float32), 8, 7, rounding=\"nearest\").item()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "# there is 1 bit for sign" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0156, -0.0859, -0.0078, ..., 0.0938, 0.0000, -0.1641])" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stochastic_rounded" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0156, -0.0859, -0.0078, ..., 0.0938, 0.0000, -0.1641])" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stochastic_rounded" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "bytes_array = stochastic_rounded.numpy().tobytes()" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "numpy.ndarray" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.ndarray" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0, 0, 128, ..., 0, 40, 190], dtype=uint8)" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.frombuffer(bytes_array, dtype = np.uint8)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "40399" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(pickle.dumps(stochastic_rounded))" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "36855" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(pickle.dumps(fpzip.compress(stochastic_rounded.numpy())))" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "FloatingPoint (exponent=3, mantissa=5)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "FloatingPoint(3,5)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "40399" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(pickle.dumps(at))" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "37119" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(pickle.dumps(fpzip.compress(at.numpy())))" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10000" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(at)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10000 torch.float32\n" + ] + } + ], + "source": [ + "print(len(stochastic_rounded), stochastic_rounded.dtype)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.3202)" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(at - stochastic_rounded, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "#backend = 'fbgemm' if x86 else 'qnnpack'\n", + "#qconfig = torch.quantization.get_default_qconfig(backend) \n", + "#torch.backends.quantized.engine = backend" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'fbgemm'" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.backends.quantized.engine" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MinMaxObserver (tensor([0.0031]), tensor([123], dtype=torch.int32))\n", + "MovingAverageMinMaxObserver (tensor([0.0031]), tensor([123], dtype=torch.int32))\n", + "HistogramObserver (tensor([0.0031]), tensor([123], dtype=torch.int32))\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/jeffrey/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/ao/quantization/observer.py:886: UserWarning: __floordiv__ is deprecated, and its behavior will change in a future version of pytorch. It currently rounds toward 0 (like the 'trunc' function NOT 'floor'). This results in incorrect rounding for negative values. To keep the current behavior, use torch.div(a, b, rounding_mode='trunc'), or for actual floor division, use torch.div(a, b, rounding_mode='floor').\n", + " src_bin_begin // dst_bin_width, 0, self.dst_nbins - 1\n", + "/home/jeffrey/anaconda3/envs/sacs39/lib/python3.9/site-packages/torch/ao/quantization/observer.py:891: UserWarning: __floordiv__ is deprecated, and its behavior will change in a future version of pytorch. It currently rounds toward 0 (like the 'trunc' function NOT 'floor'). This results in incorrect rounding for negative values. To keep the current behavior, use torch.div(a, b, rounding_mode='trunc'), or for actual floor division, use torch.div(a, b, rounding_mode='floor').\n", + " src_bin_end // dst_bin_width, 0, self.dst_nbins - 1\n" + ] + } + ], + "source": [ + "a = np.random.normal(0, 0.1, 10000).astype(np.float32)\n", + "scheme = torch.per_tensor_affine#per_tensor_affine # affine means taking into account the actual range of the values\n", + "observers = [MinMaxObserver(qscheme=scheme), MovingAverageMinMaxObserver(qscheme=scheme), HistogramObserver(qscheme=scheme)]\n", + "for obs in observers:\n", + " #for x in inputs: obs(x) \n", + " obs.forward(torch.tensor(a))#(torch.tensor(a))\n", + " print(obs.__class__.__name__, obs.calculate_qparams())" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "o = observers[0].calculate_qparams()" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(tensor([0.0031]), tensor([123], dtype=torch.int32))" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "o" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([0.0031])" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "o[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "aq = _quantize_weight(torch.tensor(a), observers[2])" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0124, 0.0124, -0.0838, ..., -0.0217, -0.1644, 0.0124],\n", + " size=(10000,), dtype=torch.qint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.003101914655417204,\n", + " zero_point=123)" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "aq" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0248, 0.0838, -0.0838, ..., -0.0217, -0.1645, 0.1738],\n", + " size=(10000,), dtype=torch.quint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.003103430150076747,\n", + " zero_point=123)" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.quantize_per_tensor(\n", + " torch.tensor(a),\n", + " o[0].item(), o[1].item(), torch.quint8)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "qt = torch.quantize_per_tensor(\n", + " torch.tensor(a),\n", + " o[0].item(), o[1].item(), torch.quint8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "qscheme=torch.qint8" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0124, 0.0124, -0.0838, ..., -0.0217, -0.1644, 0.0124],\n", + " size=(10000,), dtype=torch.qint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.003101914655417204,\n", + " zero_point=123)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "aq" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.003101914655417204" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "aq.q_scale()" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "123" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "aq.q_zero_point()" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(127, dtype=torch.int8)" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "aq.int_repr().max()" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAD8CAYAAACMwORRAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAQCklEQVR4nO3df6zddX3H8edrFNCos/y4a1hbV4zNHH9MJA3DaBYHE/lhLEvQYMzosEmTDTONS1wdicZsS2BLZJIYXSNmZWECooZO2bTyI2Z/gBZFLKDjwiBtU2jllxqiG/reH+dTPNR7e8/91XvPh+cjOTmf7/v7Oef7+aT3vvrt5/s9p6kqJEl9+Y2lHoAkaeEZ7pLUIcNdkjpkuEtShwx3SeqQ4S5JHRop3JM8muT7Se5NsqvVTkyyM8lD7fmEVk+Sa5JMJrkvyRmLOQFJ0q+bzZn7H1XV6VW1oW1vBW6rqvXAbW0b4HxgfXtsAT69UIOVJI1mPssyG4Htrb0duGiofl0N3AWsTHLKPI4jSZqlFSP2K+DrSQr456raBqyqqv1t/+PAqtZeDewZeu3eVtvPNE4++eRat27dbMYtSS9599xzz4+qamKqfaOG+1uqal+S3wJ2JvnB8M6qqhb8I0uyhcGyDa95zWvYtWvXbF4uSS95SR6bbt9IyzJVta89HwC+DJwJPHFouaU9H2jd9wFrh16+ptUOf89tVbWhqjZMTEz5F48kaY5mDPckr0jyqkNt4FxgN7AD2NS6bQJuae0dwKXtrpmzgGeHlm8kSUfBKMsyq4AvJznU/9+q6j+TfBu4Kclm4DHg3a3/rcAFwCTwHHDZgo9aknREM4Z7VT0CvGGK+pPAOVPUC7h8QUYnSZoTP6EqSR0y3CWpQ4a7JHXIcJekDhnuktShUT+hKuklaN3Wr77QfvTKC5dwJJotz9wlqUOGuyR1yHCXpA4Z7pLUIcNdkjpkuEtShwx3SeqQ4S5JHTLcJalDhrskdchwl6QOGe6S1CHDXZI6ZLhLUocMd0nqkOEuSR0y3CWpQ4a7JHXIcJekDhnuktQhw12SOmS4S1KHDHdJ6pDhLkkdMtwlqUOGuyR1yHCXpA4Z7pLUIcNdkjo0crgnOSbJd5N8pW2fmuTuJJNJbkxyXKsf37Yn2/51izR2SdI0ZnPm/gHgwaHtq4Crq+p1wNPA5lbfDDzd6le3fpKko2ikcE+yBrgQ+GzbDnA2cHPrsh24qLU3tm3a/nNaf0nSUTLqmfs/AR8Gftm2TwKeqarn2/ZeYHVrrwb2ALT9z7b+kqSjZMZwT/IO4EBV3bOQB06yJcmuJLsOHjy4kG8tSS95o5y5vxl4Z5JHgRsYLMd8EliZZEXrswbY19r7gLUAbf+rgScPf9Oq2lZVG6pqw8TExLwmIUl6sRnDvao+UlVrqmodcAlwe1W9F7gDuLh12wTc0to72jZt/+1VVQs6aknSEc3nPve/Bj6UZJLBmvq1rX4tcFKrfwjYOr8hSpJma8XMXX6lqu4E7mztR4Azp+jzM+BdCzA2SdIc+QlVSeqQ4S5JHTLcJalDhrskdchwl6QOGe6S1CHDXZI6ZLhLUocMd0nqkOEuSR0y3CWpQ4a7JHXIcJekDhnuktQhw12SOmS4S1KHDHdJ6pDhLkkdMtwlqUOGuyR1yHCXpA4Z7pLUIcNdkjpkuEtShwx3SeqQ4S5JHTLcJalDhrskdchwl6QOGe6S1CHDXZI6ZLhLUocMd0nqkOEuSR2aMdyTvCzJt5J8L8n9ST7e6qcmuTvJZJIbkxzX6se37cm2f90iz0GSdJhRztx/DpxdVW8ATgfOS3IWcBVwdVW9Dnga2Nz6bwaebvWrWz9J0lE0Y7jXwE/b5rHtUcDZwM2tvh24qLU3tm3a/nOSZKEGLEma2Uhr7kmOSXIvcADYCTwMPFNVz7cue4HVrb0a2APQ9j8LnLSAY5YkzWCkcK+qX1TV6cAa4Ezg9fM9cJItSXYl2XXw4MH5vp0kacis7papqmeAO4A3ASuTrGi71gD7WnsfsBag7X818OQU77WtqjZU1YaJiYm5jV6SNKVR7paZSLKytV8OvA14kEHIX9y6bQJuae0dbZu2//aqqgUcsyRpBitm7sIpwPYkxzD4y+CmqvpKkgeAG5L8HfBd4NrW/1rgX5NMAk8BlyzCuCVJRzBjuFfVfcAbp6g/wmD9/fD6z4B3LcjoJElz4idUJalDhrskdchwl6QOGe6S1CHDXZI6ZLhLUocMd0nqkOEuSR0y3CWpQ4a7JHXIcJekDhnuktQhw12SOmS4S1KHDHdJ6pDhLkkdMtwlqUOGuyR1yHCXpA4Z7pLUIcNdkjpkuEtShwx3SeqQ4S5JHTLcJalDhrskdchwl6QOGe6S1CHDXZI6ZLhLUocMd0nqkOEuSR0y3CWpQ4a7JHVoxnBPsjbJHUkeSHJ/kg+0+olJdiZ5qD2f0OpJck2SyST3JTljsSchSXqxUc7cnwf+qqpOA84CLk9yGrAVuK2q1gO3tW2A84H17bEF+PSCj1qSdEQzhntV7a+q77T2T4AHgdXARmB767YduKi1NwLX1cBdwMokpyz0wCVJ05vVmnuSdcAbgbuBVVW1v+16HFjV2quBPUMv29tqkqSjZORwT/JK4IvAB6vqx8P7qqqAms2Bk2xJsivJroMHD87mpZKkGYwU7kmOZRDs11fVl1r5iUPLLe35QKvvA9YOvXxNq71IVW2rqg1VtWFiYmKu45ckTWGUu2UCXAs8WFWfGNq1A9jU2puAW4bql7a7Zs4Cnh1avpEkHQUrRujzZuBPge8nubfV/ga4ErgpyWbgMeDdbd+twAXAJPAccNlCDliSNLMZw72q/gvINLvPmaJ/AZfPc1ySpHnwE6qS1CHDXZI6ZLhLUocMd0nqkOEuSR0y3CWpQ4a7JHXIcJekDhnuktQhw12SOmS4S1KHDHdJ6pDhLkkdMtwlqUOGuyR1yHCXpA4Z7pLUIcNdkjpkuEtShwx3SeqQ4S5JHTLcJalDhrskdchwl6QOGe6S1CHDXZI6ZLhLUocMd0nqkOEuSR0y3CWpQ4a7JHXIcJekDhnuktQhw12SOjRjuCf5XJIDSXYP1U5MsjPJQ+35hFZPkmuSTCa5L8kZizl4SdLURjlz/xfgvMNqW4Hbqmo9cFvbBjgfWN8eW4BPL8wwJUmzMWO4V9U3gacOK28Etrf2duCiofp1NXAXsDLJKQs0VknSiOa65r6qqva39uPAqtZeDewZ6re31SRJR9G8L6hWVQE129cl2ZJkV5JdBw8enO8wJElD5hruTxxabmnPB1p9H7B2qN+aVvs1VbWtqjZU1YaJiYk5DkOSNJW5hvsOYFNrbwJuGapf2u6aOQt4dmj5RpJ0lKyYqUOSzwNvBU5Oshf4GHAlcFOSzcBjwLtb91uBC4BJ4DngskUYsyRpBjOGe1W9Z5pd50zRt4DL5zsoSdL8+AlVSeqQ4S5JHTLcJalDhrskdchwl6QOGe6S1KEZb4WU1Kd1W7/6QvvRKy9cwpFoMXjmLkkdMtwlqUOGuyR1yDV3SS8yvBav8WW4Sy8hBvdLh8syktQhz9wleUbfIc/cJalDhrskdchlGalzLrm8NBnuUocMdLksI0kdMtwlqUOGuyR1yHCXpA55QVXqhBdRNcwzd0nqkOEuSR0y3CWpQ665S2PMdXZNx3CXxoyBrlG4LCNJHTLcJalDhrskdchwl6QOeUFVWqaGL5w+euWFSzgSjSPP3CWpQ565S8vIdLc5evujZmtRwj3JecAngWOAz1bVlYtxHKkHBrcWw4IvyyQ5BvgUcD5wGvCeJKct9HEkSdNbjDP3M4HJqnoEIMkNwEbggUU4ljSWPFvXYluMcF8N7Bna3gv8wSIcR1pS093NYnBrOViyC6pJtgBb2uZPk/xwjm91MvCjhRnVknMuy89I88hVR2Ek8zevP5NlNsdefr5gfnP5nel2LEa47wPWDm2vabUXqaptwLb5HizJrqraMN/3WQ6cy/LTyzzAuSxXizWXxbjP/dvA+iSnJjkOuATYsQjHkSRNY8HP3Kvq+STvB77G4FbIz1XV/Qt9HEnS9BZlzb2qbgVuXYz3nsK8l3aWEeey/PQyD3Auy9WizCVVtRjvK0laQn63jCR1aKzCPcnfJrkvyb1Jvp7kt1s9Sa5JMtn2nzH0mk1JHmqPTUs3+hdL8o9JftDG++UkK4f2faTN5YdJ3j5UP6/VJpNsXZKBHybJu5Lcn+SXSTYctm9s5jGVcRnnIUk+l+RAkt1DtROT7Gw//zuTnNDq0/7OLLUka5PckeSB9rP1gVYfx7m8LMm3knyvzeXjrX5qkrvbmG9sN5+Q5Pi2Pdn2r5vzwatqbB7Abw61/xL4TGtfAPwHEOAs4O5WPxF4pD2f0NonLPU82tjOBVa09lXAVa19GvA94HjgVOBhBhemj2nt1wLHtT6nLYN5/B7wu8CdwIah+ljNY4p5jcU4DxvzHwJnALuHav8AbG3trUM/Z1P+ziyHB3AKcEZrvwr47/bzNI5zCfDK1j4WuLuN8Sbgklb/DPDnrf0XQ7l2CXDjXI89VmfuVfXjoc1XAIcuGGwErquBu4CVSU4B3g7srKqnquppYCdw3lEd9DSq6utV9XzbvIvB5wFgMJcbqurnVfU/wCSDr3R44Wsdqup/gUNf67CkqurBqprqA2hjNY8pjMs4X1BV3wSeOqy8Edje2tuBi4bqU/3OLLmq2l9V32ntnwAPMvjk+zjOparqp23z2PYo4Gzg5lY/fC6H5ngzcE6SzOXYYxXuAEn+Pske4L3AR1t5qq88WH2E+nLzPgZnHjD+czlk3OcxLuOcyaqq2t/ajwOrWnss5teWJd7I4Ix3LOeS5Jgk9wIHGJxgPgw8M3RyNzzeF+bS9j8LnDSX4y67cE/yjSS7p3hsBKiqK6pqLXA98P6lHe2RzTSX1ucK4HkG81mWRpmHlr8a/Ft/bG6PS/JK4IvABw/7V/tYzaWqflFVpzP41/mZwOuPxnGX3X/WUVV/PGLX6xncS/8xpv/Kg33AWw+r3znvQY5oprkk+TPgHcA57YcVjvz1DTN+rcNimMWfybBlN49ZGulrNMbAE0lOqar9baniQKsv6/klOZZBsF9fVV9q5bGcyyFV9UySO4A3MVg6WtHOzofHe2gue5OsAF4NPDmX4y27M/cjSbJ+aHMj8IPW3gFc2q6anwU82/759jXg3CQntCvr57baksvgPzT5MPDOqnpuaNcO4JJ21fxUYD3wLcbvax3GfR7jMs6Z7AAO3SW2CbhlqD7V78ySa2vM1wIPVtUnhnaN41wm0u6ES/Jy4G0MriHcAVzcuh0+l0NzvBi4fejEb3aW+mrybB4M/ibfDdwH/Duwun51RfpTDNayvs+L79p4H4OLeZPAZUs9h6FxTTJYW7u3PT4ztO+KNpcfAucP1S9gcOfAw8AVSz2HNqY/YbBm+HPgCeBr4ziPaeY2FuMcGu/ngf3A/7U/k80M1mtvAx4CvgGc2PpO+zuz1A/gLQyWXO4b+v24YEzn8vvAd9tcdgMfbfXXMjjZmQS+ABzf6i9r25Nt/2vnemw/oSpJHRqrZRlJ0mgMd0nqkOEuSR0y3CWpQ4a7JHXIcJekDhnuktQhw12SOvT/DCIxoj6P6T0AAAAASUVORK5CYII=\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(aq.int_repr().to(torch.float32).numpy()[0:1000], 100, (-300, 300))" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(qt.int_repr().to(torch.float32).numpy()[0:1000], 100, (-300, 300))" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [], + "source": [ + "def convert(aq):\n", + " return (aq.int_repr().to(torch.float32) - aq.q_zero_point())*aq.q_scale()" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([ 0.0124, 0.0124, -0.0838, ..., -0.0217, -0.1644, 0.0124],\n", + " size=(10000,), dtype=torch.qint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.003101914655417204,\n", + " zero_point=123)\n" + ] + } + ], + "source": [ + "print(aq)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 0.0124, 0.0124, -0.0838, ..., -0.0217, -0.1644, 0.0124])" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "convert(aq)" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([127, 127, 96, ..., 116, 70, 127], dtype=torch.int8)" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "aq.int_repr()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "a = np.random.rand(100).astype(np.float32)\n", + "at = torch.from_numpy(a)\n", + "scheme = torch.per_tensor_affine\n", + "observer = MovingAverageMinMaxObserver(qscheme=scheme) #MinMaxObserver, MovingAverageMinMaxObserver(qscheme=scheme), HistogramObserver(qscheme=scheme)]\n", + "observer.forward(at)\n", + "o = observer.calculate_qparams()\n", + "aq = torch.quantize_per_tensor(\n", + " torch.tensor(a),\n", + " o[0].item(), o[1].item(), torch.quint8)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.010789979249238968" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(at - convert(aq), 2).item()" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "comp = ebit8q.compress_float(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "decomp = ebit8q.decompress_float(comp)" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.010789979249238968" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(at - decomp, 2).item()" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [], + "source": [ + "def comp(a):\n", + " b = fpzip.compress(a , precision=14, order='C')\n", + " c = fpzip.decompress(b, order='C')\n", + " bb = compress(a, tolerance=0.001, parallel=False)\n", + " cc = decompress(bb, a.shape, a.dtype, tolerance=0.001)\n", + " \n", + " at = torch.from_numpy(a)\n", + " stochastic_rounded = float_quantize(at, exp=5, man=2, rounding=\"stochastic\")\n", + " \n", + " scheme = torch.per_tensor_affine#per_tensor_affine # affine means taking into account the actual range of the values\n", + " observer = MovingAverageMinMaxObserver(qscheme=scheme) #MinMaxObserver, MovingAverageMinMaxObserver(qscheme=scheme), HistogramObserver(qscheme=scheme)]\n", + " observer.forward(at)\n", + " o = observer.calculate_qparams()\n", + " # or observer(at)\n", + " #aq = _quantize_weight(at, observer), this method does not work well!\n", + " aq = torch.quantize_per_tensor(\n", + " torch.tensor(a),\n", + " o[0].item(), o[1].item(), torch.quint8)\n", + " print(a[0:10], aq[0:10])\n", + " print(np.linalg.norm((a-c)[0][0], 2), np.linalg.norm((a-cc), 2), torch.norm(at - stochastic_rounded, 2).item(), torch.norm(at - convert(aq), 2).item())\n", + " print(\"compression_ratio:\", len(b)/(len(a)*4), len(bb)/(len(a)*4), 0.25, 0.25)\n", + " return aq" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [], + "source": [ + "def flatten_model(state_dict):\n", + " shapes = []\n", + " lens = []\n", + " tensors_to_cat = []\n", + " for _, v in state_dict.items():\n", + " shapes.append(v.shape)\n", + " t = v.flatten()\n", + " lens.append(t.shape[0])\n", + " tensors_to_cat.append(t)\n", + " return torch.cat(tensors_to_cat)" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [], + "source": [ + "a = np.random.rand(100).astype(np.float32)" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.14649276, 0.8268811 , 0.07076293, 0.41617852, 0.535295 ,\n", + " 0.09393147, 0.4459402 , 0.97720236, 0.58554167, 0.3981123 ],\n", + " dtype=float32)" + ] + }, + "execution_count": 104, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0.14649276 0.8268811 0.07076293 0.41617852 0.535295 0.09393147\n", + " 0.4459402 0.97720236 0.58554167 0.3981123 ] tensor([0.1465, 0.8287, 0.0694, 0.4163, 0.5357, 0.0925, 0.4471, 0.9790, 0.5858,\n", + " 0.3970], size=(10,), dtype=torch.quint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.0038542263209819794,\n", + " zero_point=0)\n", + "0.06702854 0.006093391 0.3343985676765442 0.011288280598819256\n", + "compression_ratio: 0.3525 0.42 0.25 0.25\n" + ] + } + ], + "source": [ + "qt = comp(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": {}, + "outputs": [], + "source": [ + "def comp16(a):\n", + " b = fpzip.compress(a , precision=18, order='C')\n", + " c = fpzip.decompress(b, order='C')\n", + " \n", + " at = torch.from_numpy(a)\n", + " stochastic_rounded = float_quantize(at, exp=5, man=2, rounding=\"stochastic\")\n", + " \n", + " scheme = torch.per_tensor_affine#per_tensor_affine # affine means taking into account the actual range of the values\n", + " observer = MovingAverageMinMaxObserver(qscheme=scheme) #MinMaxObserver, MovingAverageMinMaxObserver(qscheme=scheme), HistogramObserver(qscheme=scheme)]\n", + " observer.forward(at)\n", + " o = observer.calculate_qparams()\n", + " # or observer(at)\n", + " #aq = _quantize_weight(at, observer), this method does not work well!\n", + " aq = torch.quantize_per_tensor(\n", + " torch.tensor(a),\n", + " o[0].item(), o[1].item(), torch.quint8)\n", + " print(a[0:10], aq[0:10])\n", + " print(np.linalg.norm((a-c)[0][0], 2), torch.norm(at - stochastic_rounded, 2).item(), torch.norm(at - convert(aq), 2).item())\n", + " print(\"compression_ratio:\", len(b)/(len(a)*4), 0.25, 0.25)\n", + " return aq" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Data type float16 must be a floating type.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [90]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m qt \u001b[38;5;241m=\u001b[39m \u001b[43mcomp16\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfloat16\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n", + "Input \u001b[0;32mIn [89]\u001b[0m, in \u001b[0;36mcomp16\u001b[0;34m(a)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcomp16\u001b[39m(a):\n\u001b[0;32m----> 2\u001b[0m b \u001b[38;5;241m=\u001b[39m \u001b[43mfpzip\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcompress\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma\u001b[49m\u001b[43m \u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprecision\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m18\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43morder\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mC\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m c \u001b[38;5;241m=\u001b[39m fpzip\u001b[38;5;241m.\u001b[39mdecompress(b, order\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mC\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 5\u001b[0m at \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mfrom_numpy(a)\n", + "File \u001b[0;32mfpzip.pyx:91\u001b[0m, in \u001b[0;36mfpzip.compress\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: Data type float16 must be a floating type." + ] + } + ], + "source": [ + "qt = comp16(a.astype(np.float16))" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(qt.int_repr().to(torch.float32).numpy(), 100, (0, 300))" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": {}, + "outputs": [], + "source": [ + "a = (np.random.rand(10000).astype(np.float32) -0.5) *10" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-4.3329406 , 2.0941095 , -0.43923616, 0.24154782, 3.528521 ,\n", + " -2.766264 , -0.47501475, 0.7699454 , 0.90143025, -4.2246346 ],\n", + " dtype=float32)" + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a[0:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-4.3329406 2.0941095 -0.43923616 0.24154782 3.528521 -2.766264\n", + " -0.47501475 0.7699454 0.90143025 -4.2246346 ] tensor([-4.3515, 2.0778, -0.4312, 0.2352, 3.5283, -2.7834, -0.4704, 0.7841,\n", + " 0.9017, -4.2339], size=(10,), dtype=torch.quint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.039202895015478134,\n", + " zero_point=127)\n", + "4.052173 0.016632441 23.100893020629883 1.1358001232147217\n", + "compression_ratio: 0.3867 0.5506 0.25 0.25\n" + ] + } + ], + "source": [ + "qt = comp(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(qt.int_repr().to(torch.float32).numpy(), 100, (0, 300))" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-0.17422378 -0.17071381 0.00554137 -0.02331001 0.03649271 0.08106142\n", + " 0.05222103 -0.13010341 -0.16420947 0.04394973] tensor([-0.1739, -0.1712, 0.0054, -0.0245, 0.0353, 0.0815, 0.0516, -0.1304,\n", + " -0.1630, 0.0435], size=(10,), dtype=torch.quint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.0027172896079719067,\n", + " zero_point=126)\n", + "0.1308374 0.1322985 0.7414445281028748 0.07875864207744598\n", + "compression_ratio: 0.3656 0.302 0.25 0.25\n" + ] + } + ], + "source": [ + "a = np.random.normal(0, 0.1, 10000).astype(np.float32)\n", + "qt = comp(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 112, + "metadata": {}, + "outputs": [], + "source": [ + " bb = compress(a, tolerance=0.001, parallel=False)\n", + " cc = decompress(bb, a.shape, a.dtype, tolerance=0.001)" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [], + "source": [ + " cc = decompress(np.array(bb).tobytes(), a.shape, a.dtype, tolerance=0.001)" + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.14685059, 0.8272705 , 0.07067871, 0.4161377 , 0.5352783 ,\n", + " 0.09411621, 0.44592285, 0.977417 , 0.58569336, 0.39819336,\n", + " 0.6730957 , 0.03930664, 0.45550537, 0.75909424, 0.93377686,\n", + " 0.59088135, 0.03643799, 0.9828491 , 0.35211182, 0.24383545,\n", + " 0.01055908, 0.00189209, 0.13970947, 0.24627686, 0.06787109,\n", + " 0.74121094, 0.5839844 , 0.87353516, 0.39404297, 0.55029297,\n", + " 0.5673828 , 0.28515625, 0.46887207, 0.90270996, 0.7393799 ,\n", + " 0.7327881 , 0.19091797, 0.87109375, 0.04248047, 0.5761719 ,\n", + " 0.42425537, 0.21954346, 0.9767456 , 0.04937744, 0.708313 ,\n", + " 0.05804443, 0.62750244, 0.51239014, 0.8782959 , 0.18518066,\n", + " 0.6590576 , 0.48742676, 0.12817383, 0.42944336, 0.7199707 ,\n", + " 0.92163086, 0.24468994, 0.8966675 , 0.3772583 , 0.7821655 ,\n", + " 0.9729614 , 0.96136475, 0.41363525, 0.5739136 , 0.7182617 ,\n", + " 0.5683594 , 0.12109375, 0.89990234, 0.29241943, 0.01593018,\n", + " 0.19989014, 0.2798462 , 0.49334717, 0.31988525, 0.22454834,\n", + " 0.80303955, 0.08361816, 0.9276123 , 0.29406738, 0.6204834 ,\n", + " 0.33605957, 0.7904053 , 0.25598145, 0.4515381 , 0.40979004,\n", + " 0.10681152, 0.3433838 , 0.36169434, 0.39416504, 0.25134277,\n", + " 0.6998291 , 0.32556152, 0.7110596 , 0.21276855, 0.98010254,\n", + " 0.9661865 , 0.04711914, 0.9538574 , 0.20532227, 0.7858887 ],\n", + " dtype=float32)" + ] + }, + "execution_count": 120, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cc" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "192" + ] + }, + "execution_count": 116, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(np.array(bb).tobytes())" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "192" + ] + }, + "execution_count": 118, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(bb)" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "400" + ] + }, + "execution_count": 117, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(a.tobytes())" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(a, 100, (-0.5,0.5))" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(qt.int_repr().to(torch.float32).numpy(), 100, (0, 300))" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [], + "source": [ + "import torchvision" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [], + "source": [ + "r18 = torchvision.models.resnet18(True)" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [], + "source": [ + "flat = flatten_model(r18.state_dict())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-0.01041935 -0.00613561 -0.00180978 0.07484142 0.05661485 0.01708333\n", + " -0.01269388 0.01108271 0.00952757 -0.10992692] tensor([ 0.0000, 0.0000, 0.0000, 0.0652, 0.0652, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, -0.1305], size=(10,), dtype=torch.quint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.06523405760526657,\n", + " zero_point=45)\n", + "1.3827991 0.5653769 7.915776252746582 52.67439651489258\n", + "compression_ratio: 0.3207514668609603 0.3097713573964291 0.25 0.25\n" + ] + }, + { + "data": { + "text/plain": [ + "tensor([0., 0., 0., ..., 0., 0., 0.], size=(11699132,), dtype=torch.quint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.06523405760526657,\n", + " zero_point=45)" + ] + }, + "execution_count": 111, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "comp(flat.numpy())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 547, + "metadata": {}, + "outputs": [], + "source": [ + "def comp2(a):\n", + " b = fpzip.compress(a , precision=12, order='C')\n", + " c = fpzip.decompress(b, order='C')\n", + " \n", + " at = torch.from_numpy(a)\n", + " stochastic_rounded = float_quantize(at, exp=5, man=2, rounding=\"stochastic\")\n", + " \n", + " scheme = torch.per_tensor_symmetric#per_tensor_affine # affine means taking into account the actual range of the values\n", + " observer = HistogramObserver(qscheme=scheme) #MinMaxObserver, MovingAverageMinMaxObserver(qscheme=scheme), HistogramObserver(qscheme=scheme)]\n", + " observer.forward(at)\n", + " o = observer.calculate_qparams()\n", + " # or observer(at)\n", + " #aq = _quantize_weight(at, observer), this method does not work well!\n", + " aq = torch.quantize_per_tensor(\n", + " torch.tensor(a),\n", + " o[0].item(), o[1].item(), torch.quint8)\n", + " print(a[0:10], aq[0:10])\n", + " print(np.linalg.norm((a-c)[0][0], 2), torch.norm(at - stochastic_rounded, 2).item(), torch.norm(at - convert(aq), 2).item())\n", + " print(\"compression_ratio:\", len(b)/(len(a)*4), 0.25, 0.25)" + ] + }, + { + "cell_type": "code", + "execution_count": 468, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-0.01041935 -0.00613561 -0.00180978 0.07484142 0.05661485 0.01708333\n", + " -0.01269388 0.01108271 0.00952757 -0.10992692] tensor([-0.0130, 0.0000, 0.0000, 0.0780, 0.0520, 0.0130, -0.0130, 0.0130,\n", + " 0.0130, -0.1040], size=(10,), dtype=torch.quint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.013002387247979641,\n", + " zero_point=128)\n", + "5.376652 7.8146185874938965 28.545759201049805\n", + "compression_ratio: 0.2583094839856495 0.25 0.25\n" + ] + } + ], + "source": [ + "comp2(flat.numpy())" + ] + }, + { + "cell_type": "code", + "execution_count": 474, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "11699132" + ] + }, + "execution_count": 474, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(flat)" + ] + }, + { + "cell_type": "code", + "execution_count": 469, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(13.7179)" + ] + }, + "execution_count": 469, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat.max()" + ] + }, + { + "cell_type": "code", + "execution_count": 470, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(-2.9168)" + ] + }, + "execution_count": 470, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flat.min()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 471, + "metadata": {}, + "outputs": [], + "source": [ + "# these are the reasons why it is not working" + ] + }, + { + "cell_type": "code", + "execution_count": 476, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "580" + ] + }, + "execution_count": 476, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(flat[flat > 1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Implement qint compression sceme where we ignore values > 1 by sending them seperately" + ] + }, + { + "cell_type": "code", + "execution_count": 556, + "metadata": {}, + "outputs": [], + "source": [ + "flat2 = flat[(flat < 0.2)]" + ] + }, + { + "cell_type": "code", + "execution_count": 557, + "metadata": {}, + "outputs": [], + "source": [ + "flat3 = flat2[flat2 > -0.2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'flat3' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [106]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m qt \u001b[38;5;241m=\u001b[39m comp(\u001b[43mflat3\u001b[49m\u001b[38;5;241m.\u001b[39mnumpy())\n", + "\u001b[0;31mNameError\u001b[0m: name 'flat3' is not defined" + ] + } + ], + "source": [ + "qt = comp(flat3.numpy())" + ] + }, + { + "cell_type": "code", + "execution_count": 559, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(qt.int_repr().to(torch.float32).numpy(), 100, (0, 300))" + ] + }, + { + "cell_type": "code", + "execution_count": 548, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-0.01041935 -0.00613561 -0.00180978 0.07484142 0.05661485 0.01708333\n", + " -0.01269388 0.01108271 0.00952757 -0.10992692] tensor([-0.0112, -0.0056, 0.0000, 0.0730, 0.0561, 0.0168, -0.0112, 0.0112,\n", + " 0.0112, -0.1123], size=(10,), dtype=torch.quint8,\n", + " quantization_scheme=torch.per_tensor_affine, scale=0.005614420399069786,\n", + " zero_point=128)\n", + "4.759155 6.922706604003906 5.910922527313232\n", + "compression_ratio: 0.2583142617722315 0.25 0.25\n" + ] + } + ], + "source": [ + "comp2(flat3.numpy())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# need non linear quantization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "import pywt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "# removing bn layers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "resw = r18.state_dict()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "resw = {k:v for k,v in resw.items() if \"bn1.\" not in k}\n", + "resw = {k:v for k,v in resw.items() if \"bn2.\" not in k}\n", + "resw = {k:v for k,v in resw.items() if len(v.shape) >1}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(102.5824)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Random\n", + "probs = torch.rand_like(flat)\n", + "indices = probs < 0.1\n", + "top10_og = torch.zeros(len(flat))\n", + "top10_og[indices] = flat[indices]\n", + "torch.norm(top10_og - flat, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 102.74525451660156 185069.125\n", + "db1 103.23194122314453 185122.640625\n", + "sym2 103.66918182373047 184979.96875\n", + "coif1 102.05806732177734 184744.890625\n", + "bior1.1 102.97911834716797 185177.625\n", + "rbio1.1 103.00313568115234 185171.53125\n" + ] + } + ], + "source": [ + "# Random\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "# wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " probs = torch.rand_like(torch.from_numpy(array))\n", + " indices = probs < 0.1\n", + " \n", + " top10 = torch.zeros(len(array))\n", + " top10[indices] = torch.from_numpy(array[indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(25.6738)" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk_og = torch.topk(\n", + " flat.abs(), round(0.33*len(flat)), dim=0, sorted=False\n", + " )\n", + "top10_og = torch.zeros(len(flat))\n", + "top10_og[topk_og.indices] = flat[topk_og.indices]\n", + "torch.norm(top10_og - flat, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([11699132])\n" + ] + } + ], + "source": [ + "print(flat.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 20.19877052307129 53562.796875\n", + "db1 20.19877052307129 53562.796875\n", + "sym2 20.11495018005371 53570.296875\n", + "min: tensor(20.1150) sym2 2\n" + ] + } + ], + "source": [ + "# Base case on flattened data, with level=4\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2']#, 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "# wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.33*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.9491062664912424" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# RMSE\n", + "import math\n", + "wv = math.sqrt(42.6776)\n", + "tpk = math.sqrt(47.3773)\n", + "wv / tpk\n", + "# --> 0.949 --> 5% less error" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.8851460621415522" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wv = math.sqrt(20.1150)\n", + "tpk = math.sqrt(25.6738)\n", + "wv / tpk\n", + "# --> 0.88 --> 12% less error\n" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "# level 4: 42.677608489990234 114424.265625\n", + "# None: 42.69436264038086 114436.171875" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "approx = coeff[0]\n", + "details = coeff[1:]" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.02112804, -0.12861666, 0.355115 , ..., 0.01942001,\n", + " 0.00414812, -0.02489999], dtype=float32)" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "approx" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "731195.75" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(flat) / 16" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "731198" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(approx)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "16.845043 -5.0946984 -0.00447843\n" + ] + } + ], + "source": [ + "print(approx.max(), approx.min(), approx.mean())" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX0AAAD4CAYAAAAAczaOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAASHUlEQVR4nO3df6zddX3H8ed7VNDplAI3HbaNF2O3BRNFclcwOp2itMJm+QMdbuqN6dK41czFJbPMJWw4MtwfY5ooWyNkxWwDxuZowMFqwWxLBvSiWC0Ee0FIWwu90oJuTBz63h/nc/VYz+05955zz6/P85Hc3O/38/2ccz7ve3tf38/5nO85jcxEklSHnxn0ACRJ/WPoS1JFDH1JqoihL0kVMfQlqSIrBj2AEznjjDNycnJy0MOQpJFy//33fzszJ1odG+rQn5ycZGZmZtDDkKSREhGPL3TM5R1JqoihL0kVMfQlqSKGviRVxNCXpIoY+pJUEUNfkipi6EtSRQx9SaqIoS9JFTH0Jakihr4kVcTQlxZpctvtgx6CtGSGvrQIBr5GXUehHxGPRcTXIuKBiJgpbadFxK6I2F++ryztERGfiojZiNgbEec23c906b8/IqaXpySptwx6jZPFzPTfkpnnZOZU2d8G7M7MdcDusg/wDmBd+doCXAuNkwRwBXAesB64Yv5EIY0Cw1/joJvlnU3AjrK9A7ikqf2GbLgHODUizgQ2ALsy82hmHgN2ARu7eHxJ0iJ1GvoJ/FtE3B8RW0rbqsw8XLafAFaV7dXAgabbHixtC7X/hIjYEhEzETEzNzfX4fAkSZ3oNPTfmJnn0li62RoRb2o+mJlJ48TQtczcnplTmTk1MdHyv3iU+uJEyzku9WhUdRT6mXmofD8CfJ7GmvyTZdmG8v1I6X4IWNt08zWlbaF2SVKftA39iHhxRPzc/DZwIfB1YCcwfwXONHBr2d4JvL9cxXM+8ExZBroTuDAiVpYXcC8sbdJIcravUbSigz6rgM9HxHz/v8/MOyJiD3BzRGwGHgfeXfp/AbgImAWeBT4AkJlHI+LjwJ7S78rMPNqzSqRlZMBrXLQN/cx8FHhti/angAtatCewdYH7uh64fvHDlCT1gu/IlU6g3QzfZwAaNYa+JFXE0Jekihj6klQRQ1+SKmLoS1JFDH2pBa/K0bgy9KXjLDbwPUFolBj6UhMDXOPO0Jekihj6klQRQ1/qAZeFNCoMfUmqiKEvSRUx9KWi2yUal3g0Cgx9SaqIoS9JFTH0Jakihr4kVcTQl6SKGPqSVBFDX6J3l1t62aaGnaEvSRUx9CWpIoa+JFXE0Jekihj6klQRQ1+SKmLoS1JFDH1Jqoihr6r5ZirVpuPQj4iTIuIrEXFb2T8rIu6NiNmIuCkiTi7tp5T92XJ8suk+Li/tD0fEhp5XIy2Bwa+aLGam/2Hgoab9TwDXZOargGPA5tK+GThW2q8p/YiIs4HLgFcDG4HPRMRJ3Q1fGj6T2273RKKh1VHoR8Qa4GLgs2U/gLcCt5QuO4BLyvamsk85fkHpvwm4MTOfy8xvArPA+h7UIEnqUKcz/b8C/hD4Ydk/HXg6M58v+weB1WV7NXAAoBx/pvT/UXuL2/xIRGyJiJmImJmbm+u8EmnIONvXMGob+hHxa8CRzLy/D+MhM7dn5lRmTk1MTPTjISWpGis66PMG4J0RcRHwQuClwCeBUyNiRZnNrwEOlf6HgLXAwYhYAbwMeKqpfV7zbSRJfdB2pp+Zl2fmmsycpPFC7F2Z+VvA3cClpds0cGvZ3ln2Kcfvysws7ZeVq3vOAtYB9/WsEklSW53M9BfyUeDGiPgz4CvAdaX9OuBzETELHKVxoiAz90XEzcCDwPPA1sz8QRePL0lapEWFfmZ+CfhS2X6UFlffZOb3gHctcPurgKsWO0hJUm/4jlxJqoihL0kVMfQlqSKGvqrlm6dUI0Nfkipi6EvLyGcTGjaGviRVxNCXpIoY+qqSyy6qlaEvSRUx9CWpIoa+JFXE0JeWma8faJgY+pJUEUNf1XHmrZoZ+pJUEUNfkipi6EtSRQx9SaqIoS9JFTH0VRWv3FHtDH2pDzzZaFgY+pJUEUNfkipi6EtSRQx9SaqIoS9JFTH0pT7xCh4NA0Nf1TB0JUNfkqrSNvQj4oURcV9EfDUi9kXEn5b2syLi3oiYjYibIuLk0n5K2Z8txyeb7uvy0v5wRGxYtqokSS11MtN/DnhrZr4WOAfYGBHnA58ArsnMVwHHgM2l/2bgWGm/pvQjIs4GLgNeDWwEPhMRJ/WwFklSG21DPxv+u+y+oHwl8FbgltK+A7ikbG8q+5TjF0RElPYbM/O5zPwmMAus70URkqTOdLSmHxEnRcQDwBFgF/AI8HRmPl+6HARWl+3VwAGAcvwZ4PTm9ha3aX6sLRExExEzc3Nziy5IkrSwjkI/M3+QmecAa2jMzn9puQaUmdszcyozpyYmJpbrYVQZr9yRGhZ19U5mPg3cDbweODUiVpRDa4BDZfsQsBagHH8Z8FRze4vbSJL6oJOrdyYi4tSy/SLg7cBDNML/0tJtGri1bO8s+5Tjd2VmlvbLytU9ZwHrgPt6VIc0EnzGoUHrZKZ/JnB3ROwF9gC7MvM24KPARyJilsaa/XWl/3XA6aX9I8A2gMzcB9wMPAjcAWzNzB/0shhpFBj8GqQV7Tpk5l7gdS3aH6XF1TeZ+T3gXQvc11XAVYsfpiSpF3xHriRVxNCXpIoY+pJUEUNfkipi6EtSRQx9SaqIoa+x53Xx0o8Z+pJUEUNfGgCffWhQDH1JqoihL0kVMfQ11lxGkX6SoS9JFTH0Jakihr4kVcTQl6SKGPqSVBFDXxoQryzSIBj6klQRQ19jy5m09NMMfUmqiKEvSRUx9CWpIoa+NEC+7qB+M/Q1lgxTqTVDX5IqYuhLUkUMfUmqiKEvSRUx9KUB80Vn9ZOhr7FjiEoLaxv6EbE2Iu6OiAcjYl9EfLi0nxYRuyJif/m+srRHRHwqImYjYm9EnNt0X9Ol//6ImF6+siRJrXQy038e+IPMPBs4H9gaEWcD24DdmbkO2F32Ad4BrCtfW4BroXGSAK4AzgPWA1fMnyik2vnsRP3SNvQz83Bmfrlsfxd4CFgNbAJ2lG47gEvK9ibghmy4Bzg1Is4ENgC7MvNoZh4DdgEbe1mMJOnEFrWmHxGTwOuAe4FVmXm4HHoCWFW2VwMHmm52sLQt1H78Y2yJiJmImJmbm1vM8CRJbXQc+hHxEuCfgN/PzO80H8vMBLIXA8rM7Zk5lZlTExMTvbhLSVLRUehHxAtoBP7fZeY/l+Yny7IN5fuR0n4IWNt08zWlbaF2SVKfdHL1TgDXAQ9l5l82HdoJzF+BMw3c2tT+/nIVz/nAM2UZ6E7gwohYWV7AvbC0SZL6ZEUHfd4AvA/4WkQ8UNr+CLgauDkiNgOPA+8ux74AXATMAs8CHwDIzKMR8XFgT+l3ZWYe7UUR0jyvgpFOLBrL8cNpamoqZ2ZmBj0MjZBRD/3Hrr540EPQGIiI+zNzqtUx35ErSRUx9CWpIoa+JFXE0Jekihj60hAZ9ReiNfwMfY0NA1Nqz9CXpIoY+pJUEUNfY8GlHakzhr4kVcTQl4aMz1q0nAx9SaqIoS9JFTH0Jakihr5GnmvgUucMfUmqiKEvDSGfvWi5GPqSVBFDX5IqYuhLUkUMfUmqiKGvkTbOL3iOc20aHENfkipi6Gtk1TATrqFG9ZehL0kVMfQlqSKGviRVxNCXhpzr+uolQ1+SKmLoayQ5+5WWxtCXpIq0Df2IuD4ijkTE15vaTouIXRGxv3xfWdojIj4VEbMRsTcizm26zXTpvz8ippenHEnSiXQy0/9bYONxbduA3Zm5Dthd9gHeAawrX1uAa6FxkgCuAM4D1gNXzJ8opMVyaUdaurahn5n/Dhw9rnkTsKNs7wAuaWq/IRvuAU6NiDOBDcCuzDyamceAXfz0iUTSAjzRqVeWuqa/KjMPl+0ngFVlezVwoKnfwdK2UPtPiYgtETETETNzc3NLHJ7GleEndafrF3IzM4HswVjm7297Zk5l5tTExESv7lYaeZ7w1AtLDf0ny7IN5fuR0n4IWNvUb01pW6hdktRHSw39ncD8FTjTwK1N7e8vV/GcDzxTloHuBC6MiJXlBdwLS5vUMWe6/gzUvRXtOkTEPwC/CpwREQdpXIVzNXBzRGwGHgfeXbp/AbgImAWeBT4AkJlHI+LjwJ7S78rMPP7FYUnSMmsb+pn5ngUOXdCibwJbF7if64HrFzU6SVJP+Y5cSaqIoS+NGNf11Q1DX5IqYuhrJDi7/Un+PLRUhr6GngEn9Y6hL40oT4ZaCkNfkipi6GuoOZuVesvQl0aYJ0UtlqGvoWWgdcafkxbD0Jekihj6klQRQ19DySULaXm0/ZRNqZ8Me2l5OdOXxsDktts9Yaojhr4kVcTQl8aIs321Y+hLY8bg14kY+pJUEUNfQ8MZau/4s9RCDH0NBUOq9/yZqhVDXwNnOC0fL+XU8Qx9DZSBJPWXoa+BMfD7x5+15hn66juXHAbDn7nA0FefGTyD5c9ffuCa+sbAGQ7Nv4fHrr54gCPRIDjT17KaDxgDfzj5e6lPZOagx7CgqampnJmZGfQwtEQGyuhx5j8eIuL+zJxqdczlHfWUQT/a5n9/j119MZPbbvckMIac6asnDPvx5wlgdAzVTD8iNgKfBE4CPpuZV/d7DOrO/AzQoK9Lq9+3J4LR09eZfkScBHwDeDtwENgDvCczH2zV35l+/zUHusGubh1/UnDJqD9ONNPvd+i/HviTzNxQ9i8HyMw/b9Xf0P+x4/9Yjr/sznBWTZr/zR//+kOrv5WFjo2rYQr9S4GNmfnbZf99wHmZ+aGmPluALWX3F4GHu3jIM4Bvd3H7YTEudYC1DKNxqQOsZd4rMnOi1YGhu3onM7cD23txXxExs9DZbpSMSx1gLcNoXOoAa+lEv9+cdQhY27S/prRJkvqg36G/B1gXEWdFxMnAZcDOPo9BkqrV1+WdzHw+Ij4E3Enjks3rM3PfMj5kT5aJhsC41AHWMozGpQ6wlraG+s1ZkqTe8gPXJKkihr4kVWSsQj8iTouIXRGxv3xf2aLPKyLiyxHxQETsi4gPDmKsJ9JhHedExH+VGvZGxG8MYqztdFJL6XdHRDwdEbf1e4wnEhEbI+LhiJiNiG0tjp8SETeV4/dGxOQAhtmRDmp5U/nbeL68p2ZodVDLRyLiwfK3sTsiXjGIcXaig1o+GBFfK5n1nxFxdlcPmJlj8wX8BbCtbG8DPtGiz8nAKWX7JcBjwMsHPfYl1PELwLqy/XLgMHDqoMe+lFrKsQuAXwduG/SYm8Z0EvAI8Mry7+arwNnH9fld4K/L9mXATYMedxe1TAKvAW4ALh30mLus5S3Az5bt3xnx38tLm7bfCdzRzWOO1Uwf2ATsKNs7gEuO75CZ38/M58ruKQzns51O6vhGZu4v298CjgAt34E3YG1rAcjM3cB3+zSmTq0HZjPz0cz8PnAjjXqaNdd3C3BBREQfx9iptrVk5mOZuRf44SAGuAid1HJ3Zj5bdu+h8Z6gYdRJLd9p2n0x0NXVN8MYeN1YlZmHy/YTwKpWnSJibUTsBQ7QmHl+q18D7FBHdcyLiPU0ZgmPLPfAlmBRtQyZ1TT+jcw7WNpa9snM54FngNP7MrrF6aSWUbHYWjYD/7qsI1q6jmqJiK0R8QiNZ86/180DDt3HMLQTEV8Efr7FoY8172RmRkTLM2JmHgBeExEvB/4lIm7JzCd7P9qF9aKOcj9nAp8DpjNzIDO0XtUi9VpEvBeYAt486LF0IzM/DXw6In4T+GNgeqn3NXKhn5lvW+hYRDwZEWdm5uEShkfa3Ne3IuLrwK/QeGreN72oIyJeCtwOfCwz71mmobbVy9/JkOnkY0Pm+xyMiBXAy4Cn+jO8RRmnj0DpqJaIeBuNicebm5Z0h81ify83Atd284Djtryzkx+fAaeBW4/vEBFrIuJFZXsl8Ea6+yTP5dBJHScDnwduyMy+nrAWqW0tQ6yTjw1pru9S4K4sr7gNmXH6CJS2tUTE64C/Ad6ZmcM80eiklnVNuxcD+7t6xEG/et3jV8JPB3aXH8oXgdNK+xSN/6ULGv+By14ar5LvBbYMetxLrOO9wP8BDzR9nTPosS+llrL/H8Ac8L801jU3DHrsZVwX0fiPfx6h8YwK4EoaYQLwQuAfgVngPuCVgx5zF7X8cvnZ/w+NZyv7Bj3mLmr5IvBk09/GzkGPuYtaPgnsK3XcDby6m8fzYxgkqSLjtrwjSToBQ1+SKmLoS1JFDH1JqoihL0kVMfQlqSKGviRV5P8BG17N1nxNq/MAAAAASUVORK5CYII=\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(approx, 1000, (-0.3, 0.3))" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(details)" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[731198, 1462394, 2924785, 5849567]\n" + ] + } + ], + "source": [ + "print([len(d) for d in details])" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "d0 = details[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4.3342423 -3.6128068 -5.1483516e-06\n" + ] + } + ], + "source": [ + "print(d0.max(), d0.min(), d0.mean())" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.02881567, -0.49651563, -0.06628633, ..., 0.02382721,\n", + " -0.02910749, 0.01628537], dtype=float32)" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d0" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(d0, 1000, (-0.3, 0.3))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 83.8722915649414 171346.921875\n", + "db1 83.8722915649414 171346.921875\n", + "sym2 83.61727142333984 169984.34375\n", + "min: tensor(83.6173) sym2 2\n" + ] + } + ], + "source": [ + "# Just using the approximation!\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2']#, 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "# wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " approx = coeff[0]\n", + " details = coeff[1:]\n", + " details = [np.zeros_like(d) for d in details]\n", + " approx_only = [approx]\n", + " approx_only.extend(details)\n", + " array, coeff_slices = pywt.coeffs_to_array(approx_only)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " #topk = torch.topk(\n", + " # torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " # )\n", + " #top10 = torch.zeros(len(array))\n", + " #top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(array, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "18.828228" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "array[topk.indices].max()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "-9.629911" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "array[topk.indices].min()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "sub = array[topk.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "527" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(sub[np.absolute(sub) > 1])" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1169917" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(sub)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYMAAAD4CAYAAAAO9oqkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAATcklEQVR4nO3db7Bc9X3f8ffHUsBuUowwqkIkxleeqHFJOsX4DlbiTlODLQTuWHSKXXmaoriq1cQ4k0ySSUT9gNYOU9wHIWbqOKVGRbitZUrqQQ1QVebPZDpjYS41BguKdcH2IAUjxQIcj8c44G8f7O96jsXee/dKe3evpPdrZmfP+Z7fOfvdc1f72T17dpWqQpJ0envNuBuQJI2fYSBJMgwkSYaBJAnDQJIELB93A8fr3HPPrYmJiXG3IUknjYcffvgvq2plv2UnbRhMTEwwNTU17jYk6aSR5JuzLfMwkSTJMJAkGQaSJAwDSRKGgSQJw0CShGEgScIwkCRhGEiSMAwkSRgGkiQGDIMk30jyWJJHkky12jlJ9iY50K5XtHqS3JRkOsmjSS7qbGdLG38gyZZO/a1t+9Nt3Qz7jkqSZreQdwbvqKoLq2qyzW8H7q2qdcC9bR7gcmBdu2wDPgW98ACuA94GXAxcNxMgbcwHO+ttPO57JElasBM5TLQJ2NmmdwJXduq3Vc8+4Owk5wGXAXur6mhVPQ/sBTa2ZWdV1b6qKuC2zrYkSSMwaBgU8L+TPJxkW6utqqpn2/S3gFVtejXwTGfdg602V/1gn/qrJNmWZCrJ1JEjRwZsXZI0n0H/P4O/X1WHkvwtYG+S/9ddWFWVpIbf3o+rqpuBmwEmJycX/fYk6XQx0DuDqjrUrg8Dn6d3zP+5doiHdn24DT8EnN9ZfU2rzVVf06cuSRqRecMgyU8m+Zsz08AG4KvAbmDmjKAtwJ1tejdwdTuraD3wYjuctAfYkGRF++B4A7CnLftOkvXtLKKrO9uSJI3AIIeJVgGfb2d7Lgf+W1X9ryQPAbcn2Qp8E3hfG383cAUwDXwP+ABAVR1N8jHgoTbuo1V1tE1/CLgVeB1wT7tIkkYkvRN4Tj6Tk5Pl/4Gsk8XE9rv4xg3vHncbOs0lebjz9YAf4zeQJUmGgSTJMJAkYRhIkjAMJEkYBpIkDANJEoaBJAnDQJKEYSBJwjCQJGEYSJIwDCRJGAaSJAwDSRKGgXTcJrbfNe4WpKExDCRJhoEkyTCQJGEYSJIwDCRJGAaSJAwDSRKGgSQJw0CShGEgScIwkCRhGEiSMAwkSRgGkiQMA0kSCwiDJMuSfDnJn7X5tUkeTDKd5HNJzmj1M9v8dFs+0dnGta3+ZJLLOvWNrTadZPsQ758kaQALeWfwm8ATnfmPAzdW1c8CzwNbW30r8Hyr39jGkeQCYDPw88BG4I9bwCwDPglcDlwAvL+NlSSNyEBhkGQN8G7g020+wCXAHW3ITuDKNr2pzdOWX9rGbwJ2VdVLVfV1YBq4uF2mq+rpqvoBsKuNlSSNyKDvDP4I+D3gh23+DcALVfVymz8IrG7Tq4FnANryF9v4H9WPWWe2+qsk2ZZkKsnUkSNHBmxdkjSfecMgyT8CDlfVwyPoZ05VdXNVTVbV5MqVK8fdjiSdMpYPMObtwHuSXAG8FjgL+ARwdpLl7dX/GuBQG38IOB84mGQ58Hrg2536jO46s9UlSSMw7zuDqrq2qtZU1QS9D4Dvq6p/BtwPXNWGbQHubNO72zxt+X1VVa2+uZ1ttBZYB3wJeAhY185OOqPdxu6h3DtJ0kAGeWcwm98HdiX5A+DLwC2tfgvwmSTTwFF6T+5U1f4ktwOPAy8D11TVKwBJPgzsAZYBO6pq/wn0JUlaoAWFQVU9ADzQpp+mdybQsWO+D7x3lvWvB67vU78buHshvUiShsdvIEuSDANJkmEgScIwkCRhGEiSMAwkSRgGkiQMA0kShoEkCcNAkoRhIB2Xie13jbsFaagMA0mSYSBJMgwkSRgGkiQMA0kShoEkCcNAkoRhIEnCMJAkYRhII+O3lrWUGQaSJMNAkmQYSJIwDCRJGAaSJAwDSRKGgSQJw0CShGEgScIwkCQxQBgkeW2SLyX5SpL9Sf5tq69N8mCS6SSfS3JGq5/Z5qfb8onOtq5t9SeTXNapb2y16STbF+F+SpLmMMg7g5eAS6rq7wEXAhuTrAc+DtxYVT8LPA9sbeO3As+3+o1tHEkuADYDPw9sBP44ybIky4BPApcDFwDvb2MlSSMybxhUz3fb7E+0SwGXAHe0+k7gyja9qc3Tll+aJK2+q6peqqqvA9PAxe0yXVVPV9UPgF1trCRpRAb6zKC9gn8EOAzsBZ4CXqiql9uQg8DqNr0aeAagLX8ReEO3fsw6s9UlSSMyUBhU1StVdSGwht4r+TcvZlOzSbItyVSSqSNHjoyjBUk6JS3obKKqegG4H/hF4Owky9uiNcChNn0IOB+gLX898O1u/Zh1Zqv3u/2bq2qyqiZXrly5kNYlSXMY5GyilUnObtOvA94FPEEvFK5qw7YAd7bp3W2etvy+qqpW39zONloLrAO+BDwErGtnJ51B70Pm3UO4b5KkAS2ffwjnATvbWT+vAW6vqj9L8jiwK8kfAF8GbmnjbwE+k2QaOErvyZ2q2p/kduBx4GXgmqp6BSDJh4E9wDJgR1XtH9o9lCTNa94wqKpHgbf0qT9N7/ODY+vfB947y7auB67vU78buHuAfiVJi8BvIEuSDANJkmEgScIwkCRhGEiSMAwkSRgGkiQMA0kShoEkCcNAkoRhIEnCMJAWbGL7XeNuQRo6w0CSZBhIkgwDSRKGgSQJw0CShGEgScIwkCRhGEgj5XcUtFQZBpIkw0CSZBhIkjAMJEkYBpIkDANJEoaBJAnDQJKEYSBJwjCQJGEYSJIwDCRJDBAGSc5Pcn+Sx5PsT/KbrX5Okr1JDrTrFa2eJDclmU7yaJKLOtva0sYfSLKlU39rksfaOjclyWLcWUlSf4O8M3gZ+J2qugBYD1yT5AJgO3BvVa0D7m3zAJcD69plG/Ap6IUHcB3wNuBi4LqZAGljPthZb+OJ3zVJ0qDmDYOqeraq/m+b/ivgCWA1sAnY2YbtBK5s05uA26pnH3B2kvOAy4C9VXW0qp4H9gIb27KzqmpfVRVwW2dbkqQRWNBnBkkmgLcADwKrqurZtuhbwKo2vRp4prPawVabq36wT73f7W9LMpVk6siRIwtpXZI0h4HDIMlPAX8K/FZVfae7rL2iryH39ipVdXNVTVbV5MqVKxf75iTptDFQGCT5CXpB8F+r6n+08nPtEA/t+nCrHwLO76y+ptXmqq/pU5ckjcggZxMFuAV4oqr+sLNoNzBzRtAW4M5O/ep2VtF64MV2OGkPsCHJivbB8QZgT1v2nSTr221d3dmWJGkElg8w5u3APwceS/JIq/1r4Abg9iRbgW8C72vL7gauAKaB7wEfAKiqo0k+BjzUxn20qo626Q8BtwKvA+5pF2nJ8f8w1qlq3jCoqv8DzHbe/6V9xhdwzSzb2gHs6FOfAn5hvl4kSYvDbyBLkgwDSZJhIEnCMJAkYRhIkjAMJEkYBpIkDANJEoaBJAnDQJKEYSBJwjCQRs4fu9NSZBhIkgwDSZJhIEnCMJAkYRhIkjAMJEkYBpIkDANJEoaBJAnDQJKEYSANzJ+R0KnMMJAkGQaSJMNAkoRhII2Fnz9oqTEMJEmGgSTJMJAkYRhIkhggDJLsSHI4yVc7tXOS7E1yoF2vaPUkuSnJdJJHk1zUWWdLG38gyZZO/a1JHmvr3JQkw76TkqS5DfLO4FZg4zG17cC9VbUOuLfNA1wOrGuXbcCnoBcewHXA24CLgetmAqSN+WBnvWNvS5K0yOYNg6r6c+DoMeVNwM42vRO4slO/rXr2AWcnOQ+4DNhbVUer6nlgL7CxLTurqvZVVQG3dbYlSRqR4/3MYFVVPdumvwWsatOrgWc64w622lz1g33qfSXZlmQqydSRI0eOs3Vp4fxegE51J/wBcntFX0PoZZDburmqJqtqcuXKlaO4SUk6LRxvGDzXDvHQrg+3+iHg/M64Na02V31Nn7okaYSONwx2AzNnBG0B7uzUr25nFa0HXmyHk/YAG5KsaB8cbwD2tGXfSbK+nUV0dWdbkqQRGeTU0s8CXwR+LsnBJFuBG4B3JTkAvLPNA9wNPA1MA/8J+BBAVR0FPgY81C4fbTXamE+3dZ4C7hnOXZOWNj+H0FKyfL4BVfX+WRZd2mdsAdfMsp0dwI4+9SngF+brQ5K0ePwGsiTJMJAkGQaSJAwDaV5+0KvTgWEgSTIMpHHyXYeWCsNAkmQYSJIMA0kShoEkCcNAmpMf8Op0YRhIkgwDSZJhII2dh6K0FBgGkiTDQJJkGEiSMAykWY3yWL6fG2jcDANJkmEgSTIMpL7GcdjGQ0UaJ8NAkmQYSJIMA+lVxnm4xkNFGhfDQJJkGEhdS+GV+VLoQacfw0CSZBhIM5bSK/Kl1ItOD4aBtEQZCBql5eNuQBo3n3Ql3xnoNLfUg2Bi+11LvkedGgwDnbZOpifZk6lXnZyWzGGiJBuBTwDLgE9X1Q1jbkmnoJP5SXWm92/c8O4xd6JT0ZIIgyTLgE8C7wIOAg8l2V1Vj4+3M53sTuYn/9l075PBoGFZEmEAXAxMV9XTAEl2AZsAw0A/5lR8cj8Rc+0Pg0ILsVTCYDXwTGf+IPC2Ywcl2QZsa7PfTfLkcd7eucBfHue6i8m+FmbsfeXjfctj7wv69rYk+urDvhbmRPp642wLlkoYDKSqbgZuPtHtJJmqqskhtDRU9rUw9rUw9rUwp1tfS+VsokPA+Z35Na0mSRqBpRIGDwHrkqxNcgawGdg95p4k6bSxJA4TVdXLST4M7KF3aumOqtq/iDd5woeaFol9LYx9LYx9Lcxp1VeqajG2K0k6iSyVw0SSpDEyDCRJp24YJHlvkv1Jfphk1tOwkmxM8mSS6STbO/W1SR5s9c+1D7aH0dc5SfYmOdCuV/QZ844kj3Qu309yZVt2a5Kvd5ZdOKq+2rhXOre9u1Mf5/66MMkX29/70ST/tLNsqPtrtsdLZ/mZ7f5Pt/0x0Vl2bas/meSyE+njOPr67SSPt/1zb5I3dpb1/ZuOqK9fTXKkc/v/srNsS/u7H0iyZcR93djp6WtJXugsW5T9lWRHksNJvjrL8iS5qfX8aJKLOstOfF9V1Sl5Af4O8HPAA8DkLGOWAU8BbwLOAL4CXNCW3Q5sbtN/Avz6kPr698D2Nr0d+Pg8488BjgJ/o83fCly1CPtroL6A785SH9v+Av42sK5N/wzwLHD2sPfXXI+XzpgPAX/SpjcDn2vTF7TxZwJr23aWjbCvd3QeQ78+09dcf9MR9fWrwH/os+45wNPtekWbXjGqvo4Z/xv0TmpZ7P31D4CLgK/OsvwK4B4gwHrgwWHuq1P2nUFVPVFV831D+Uc/g1FVPwB2AZuSBLgEuKON2wlcOaTWNrXtDbrdq4B7qup7Q7r92Sy0rx8Z9/6qqq9V1YE2/RfAYWDlkG6/q+/jZY5+7wAubftnE7Crql6qqq8D0217I+mrqu7vPIb20fsuz2IbZH/N5jJgb1Udrarngb3AxjH19X7gs0O67VlV1Z/Te+E3m03AbdWzDzg7yXkMaV+dsmEwoH4/g7EaeAPwQlW9fEx9GFZV1bNt+lvAqnnGb+bVD8Tr29vEG5OcOeK+XptkKsm+mUNXLKH9leRieq/2nuqUh7W/Znu89B3T9seL9PbPIOsuZl9dW+m9wpzR7286yr7+Sfv73JFk5sunS2J/tcNpa4H7OuXF2l/zma3voeyrJfE9g+OV5AvAT/dZ9JGqunPU/cyYq6/uTFVVklnP7W2p/3fpff9ixrX0nhTPoHe+8e8DHx1hX2+sqkNJ3gTcl+Qxek94x23I++szwJaq+mErH/f+OhUl+RVgEvjlTvlVf9Oqeqr/FobufwKfraqXkvwreu+qLhnRbQ9iM3BHVb3SqY1zfy2akzoMquqdJ7iJ2X4G49v03oItb6/uFvTzGHP1leS5JOdV1bPtyevwHJt6H/D5qvrrzrZnXiW/lOQ/A787yr6q6lC7fjrJA8BbgD9lzPsryVnAXfReCOzrbPu491cfg/xsysyYg0mWA6+n93hazJ9cGWjbSd5JL2B/uapemqnP8jcdxpPbvH1V1bc7s5+m9xnRzLr/8Jh1HxhCTwP11bEZuKZbWMT9NZ/Z+h7KvjrdDxP1/RmM6n0qcz+94/UAW4BhvdPY3bY3yHZfdayyPSHOHKe/Euh75sFi9JVkxcxhliTnAm8HHh/3/mp/u8/TO556xzHLhrm/BvnZlG6/VwH3tf2zG9ic3tlGa4F1wJdOoJcF9ZXkLcB/BN5TVYc79b5/0xH2dV5n9j3AE216D7Ch9bcC2MCPv0Ne1L5ab2+m94HsFzu1xdxf89kNXN3OKloPvNhe7AxnXy3Gp+JL4QL8Y3rHzl4CngP2tPrPAHd3xl0BfI1esn+kU38TvX+s08B/B84cUl9vAO4FDgBfAM5p9Ul6/8PbzLgJeon/mmPWvw94jN6T2n8BfmpUfQG/1G77K+1661LYX8CvAH8NPNK5XLgY+6vf44XeYaf3tOnXtvs/3fbHmzrrfqSt9yRw+ZAf7/P19YX272Bm/+ye7286or7+HbC/3f79wJs76/6Lth+ngQ+Msq82/2+AG45Zb9H2F70Xfs+2x/JBep/t/Brwa2156P0nYE+1257srHvC+8qfo5AknfaHiSRJGAaSJAwDSRKGgSQJw0CShGEgScIwkCQB/x8+68ScpRK0jQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "<Figure size 432x288 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "_ = plt.hist(array[topk.indices], 1000, (-1, 1))" + ] + }, + { + "cell_type": "code", + "execution_count": 171, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "11699132" + ] + }, + "execution_count": 171, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(flat)" + ] + }, + { + "cell_type": "code", + "execution_count": 172, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3420.399391883936" + ] + }, + "execution_count": 172, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.sqrt(len(flat))" + ] + }, + { + "cell_type": "code", + "execution_count": 180, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 181, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 2, 191, 15313]" + ] + }, + "execution_count": 181, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "prime_factors(len(flat))" + ] + }, + { + "cell_type": "code", + "execution_count": 182, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "764" + ] + }, + "execution_count": 182, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2*2*191" + ] + }, + { + "cell_type": "code", + "execution_count": 183, + "metadata": {}, + "outputs": [], + "source": [ + "square = flat.reshape(764, 15313)" + ] + }, + { + "cell_type": "code", + "execution_count": 225, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(765, 15317)\n", + "(765, 15317)\n", + "torch.Size([764, 15313])\n", + "haar 46.458038330078125 125166.609375\n", + "(765, 15317)\n", + "(765, 15317)\n", + "torch.Size([764, 15313])\n", + "db1 46.458038330078125 125166.609375\n", + "(774, 15322)\n", + "(774, 15322)\n", + "torch.Size([764, 15313])\n", + "sym2 46.43218231201172 125249.15625\n", + "(781, 15331)\n", + "(781, 15331)\n", + "torch.Size([764, 15313])\n", + "coif1 46.54570388793945 125596.46875\n", + "(765, 15317)\n", + "(765, 15317)\n", + "torch.Size([764, 15313])\n", + "bior1.1 46.458038330078125 125166.609375\n", + "(765, 15317)\n", + "(765, 15317)\n", + "torch.Size([764, 15313])\n", + "rbio1.1 46.458038330078125 125166.609375\n", + "(1004, 15556)\n", + "(1004, 15556)\n", + "torch.Size([764, 15313])\n", + "dmey 52.37420654296875 139893.703125\n", + "(798, 15348)\n", + "(798, 15348)\n", + "torch.Size([764, 15313])\n", + "bior4.4 47.59955978393555 128068.578125\n", + "min: tensor(46.4322) sym2 2\n" + ] + } + ], + "source": [ + "# Base case on rectangular data, with level=4\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "# wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " coeff = pywt.wavedecn(square.numpy(), wavelet, level = 4)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " shape = array.shape\n", + " print(shape)\n", + " array = torch.from_numpy(array).flatten()\n", + " topk = torch.topk(\n", + " array.abs(), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " \n", + " top10[topk.indices] = array[topk.indices]\n", + " top10 = top10.reshape(shape).numpy()\n", + " print(top10.shape)\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedecn\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverecn(og, wavelet = wavelet))\n", + " reverse_top10 = reverse_top10[0:, :-1]\n", + " print(reverse_top10.shape)\n", + " err = torch.norm(reverse_top10 - square, 2)\n", + " err1 = torch.norm(reverse_top10 - square, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [], + "source": [ + "# layerwise" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "stats = {k: l.shape for k,l in resw.items()}" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'conv1.weight': torch.Size([64, 3, 7, 7]),\n", + " 'layer1.0.conv1.weight': torch.Size([64, 64, 3, 3]),\n", + " 'layer1.0.conv2.weight': torch.Size([64, 64, 3, 3]),\n", + " 'layer1.1.conv1.weight': torch.Size([64, 64, 3, 3]),\n", + " 'layer1.1.conv2.weight': torch.Size([64, 64, 3, 3]),\n", + " 'layer2.0.conv1.weight': torch.Size([128, 64, 3, 3]),\n", + " 'layer2.0.conv2.weight': torch.Size([128, 128, 3, 3]),\n", + " 'layer2.0.downsample.0.weight': torch.Size([128, 64, 1, 1]),\n", + " 'layer2.1.conv1.weight': torch.Size([128, 128, 3, 3]),\n", + " 'layer2.1.conv2.weight': torch.Size([128, 128, 3, 3]),\n", + " 'layer3.0.conv1.weight': torch.Size([256, 128, 3, 3]),\n", + " 'layer3.0.conv2.weight': torch.Size([256, 256, 3, 3]),\n", + " 'layer3.0.downsample.0.weight': torch.Size([256, 128, 1, 1]),\n", + " 'layer3.1.conv1.weight': torch.Size([256, 256, 3, 3]),\n", + " 'layer3.1.conv2.weight': torch.Size([256, 256, 3, 3]),\n", + " 'layer4.0.conv1.weight': torch.Size([512, 256, 3, 3]),\n", + " 'layer4.0.conv2.weight': torch.Size([512, 512, 3, 3]),\n", + " 'layer4.0.downsample.0.weight': torch.Size([512, 256, 1, 1]),\n", + " 'layer4.1.conv1.weight': torch.Size([512, 512, 3, 3]),\n", + " 'layer4.1.conv2.weight': torch.Size([512, 512, 3, 3]),\n", + " 'fc.weight': torch.Size([1000, 512])}" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stats" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [], + "source": [ + "#r18.state_dict()['conv1.weight']" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([64, 3, 7, 7])" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "r18.state_dict()['conv1.weight'].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 596, + "metadata": {}, + "outputs": [], + "source": [ + "res = pywt.wavedec(r18.state_dict()['conv1.weight'].numpy(), \"sym2\")" + ] + }, + { + "cell_type": "code", + "execution_count": 597, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(64, 3, 7, 5)" + ] + }, + "execution_count": 597, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "res[1].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 598, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(64, 3, 7, 5)" + ] + }, + "execution_count": 598, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "res[0].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 600, + "metadata": {}, + "outputs": [], + "source": [ + "test_weight = r18.state_dict()['conv1.weight'].numpy()" + ] + }, + { + "cell_type": "code", + "execution_count": 602, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([-0.0104, -0.0061, -0.0018, ..., -0.0244, -0.0712, -0.0668])" + ] + }, + "execution_count": 602, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "flatten_model({\"f1\": r18.state_dict()['conv1.weight']})" + ] + }, + { + "cell_type": "code", + "execution_count": 605, + "metadata": {}, + "outputs": [], + "source": [ + "flat_v1w = flatten_model({\"f1\": r18.state_dict()['conv1.weight']}).numpy()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 618, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 630, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([])" + ] + }, + "execution_count": 630, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# resw[\"bn1.num_batches_tracked\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 47.194419860839844 124593.125\n", + "db1 47.194419860839844 124593.125\n", + "sym2 47.194419860839844 124593.125\n", + "coif1 47.194419860839844 124593.125\n", + "bior1.1 47.194419860839844 124593.125\n", + "rbio1.1 47.194419860839844 124593.125\n", + "dmey 47.194419860839844 124593.125\n", + "bior4.4 47.194419860839844 124593.125\n", + "min: tensor(47.1944) haar 0\n" + ] + } + ], + "source": [ + "# wavedecn, with level = 0\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "#wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " shape = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " coeffs = []\n", + " to_del = []\n", + " for key, v in resw.items():\n", + " #print(key, v.shape)\n", + " if v.shape == torch.Size([]):\n", + " print(key)\n", + " to_del.append(key)\n", + " continue\n", + " \n", + " coeff = pywt.wavedecn(torch.squeeze(v).numpy(), wavelet, level = 0)\n", + " #print(coeff[0].shape)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " shape.append(array.shape)\n", + " coeffs.append(coeff_slices)\n", + " #print(array.shape)\n", + " flat_array = torch.from_numpy(array).flatten()\n", + " lens.append(len(flat_array))\n", + " to_cat.append(flat_array)\n", + " for k in to_del:\n", + " del resw[k]\n", + " flat_wv = torch.cat(to_cat)\n", + " topk = torch.topk(\n", + " flat_wv.abs(), round(0.1*len(flat_wv)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_wv))\n", + " top10[topk.indices] = flat_wv[topk.indices]\n", + " \n", + " start_index = 0\n", + " state_dict = {}\n", + " for i, key in enumerate(resw):\n", + " end_index = start_index + lens[i]\n", + " #print(start_index, end_index, top10.shape)\n", + " #print(top10)\n", + " crr = top10[start_index:end_index]\n", + " #print(crr.shape)\n", + " og = pywt.array_to_coeffs(crr.reshape(shape[i]), coeffs[i], output_format=\"wavedecn\")\n", + " state_dict[key] = torch.from_numpy(pywt.waverecn(og, wavelet = wavelet))\n", + " start_index = end_index\n", + "\n", + " reverse_top10 = flatten_model(state_dict)\n", + " flat = flatten_model(resw)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(64, 3, 7, 7),\n", + " (64, 64, 3, 3),\n", + " (64, 64, 3, 3),\n", + " (64, 64, 3, 3),\n", + " (64, 64, 3, 3),\n", + " (128, 64, 3, 3),\n", + " (128, 128, 3, 3),\n", + " (128, 64),\n", + " (128, 128, 3, 3),\n", + " (128, 128, 3, 3),\n", + " (256, 128, 3, 3),\n", + " (256, 256, 3, 3),\n", + " (256, 128),\n", + " (256, 256, 3, 3),\n", + " (256, 256, 3, 3),\n", + " (512, 256, 3, 3),\n", + " (512, 512, 3, 3),\n", + " (512, 256),\n", + " (512, 512, 3, 3),\n", + " (512, 512, 3, 3),\n", + " (1000, 512)]" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## wavedecn does not work corretly for dim > 2, so we need to reshape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 152, + "metadata": {}, + "outputs": [], + "source": [ + "resw_oe = resw.copy()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 153, + "metadata": {}, + "outputs": [], + "source": [ + "del resw_oe[\"conv1.weight\"] # for this one the size is incorrect during reconstruction" + ] + }, + { + "cell_type": "code", + "execution_count": 227, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11669504 11669504\n", + "haar 45.01624298095703 121187.4765625\n", + "11669504 11669504\n", + "db1 45.01624298095703 121187.4765625\n", + "11669504 11669504\n", + "sym2 44.518096923828125 120046.953125\n", + "11669504 11669504\n", + "coif1 44.400272369384766 119750.8671875\n", + "11669504 11669504\n", + "bior1.1 45.01624298095703 121187.4765625\n", + "11669504 11669504\n", + "rbio1.1 45.01624298095703 121187.4765625\n", + "11669504 11669504\n", + "dmey 44.74907302856445 120040.7890625\n", + "11669504 11669504\n", + "bior4.4 44.85655975341797 120709.2578125\n", + "min: tensor(44.4003) coif1 3\n" + ] + } + ], + "source": [ + "# wavedecn with axes specified, on dimensions reduced to 2x2\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "#wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " shape = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " coeffs = []\n", + " to_del = []\n", + " for key, v in resw_oe.items():\n", + " #print(key, v.shape)\n", + " if v.shape == torch.Size([]):\n", + " print(key)\n", + " to_del.append(key)\n", + " continue\n", + " v = torch.squeeze(v).numpy()\n", + " if len(v.shape) > 2:\n", + " #print(v.shape)\n", + " v = v.reshape((v.shape[0], np.prod(v.shape[1:])))\n", + " #print(v.shape)\n", + " coeff = pywt.wavedecn(v, wavelet, level = None, axes = (0,1))\n", + " #print(coeff[0].shape)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff, axes = (0,1))\n", + " shape.append(array.shape)\n", + " coeffs.append(coeff_slices)\n", + " #print(array.shape)\n", + " flat_array = torch.from_numpy(array).flatten()\n", + " lens.append(len(flat_array))\n", + " to_cat.append(flat_array)\n", + " for k in to_del:\n", + " del resw_oe[k]\n", + " flat_wv = torch.cat(to_cat)\n", + " topk = torch.topk(\n", + " flat_wv.abs(), round(0.1*len(flat_wv)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_wv))\n", + " top10[topk.indices] = flat_wv[topk.indices]\n", + " \n", + " start_index = 0\n", + " state_dict = {}\n", + " for i, key in enumerate(resw_oe):\n", + " end_index = start_index + lens[i]\n", + " #print(start_index, end_index, top10.shape)\n", + " #print(top10)\n", + " crr = top10[start_index:end_index]\n", + " #print(crr.shape)\n", + " og = pywt.array_to_coeffs(crr.reshape(shape[i]), coeffs[i], output_format=\"wavedecn\")\n", + " state_dict[key] = torch.from_numpy(pywt.waverecn(og, wavelet = wavelet, axes = (0,1)))\n", + " # print(state_dict[key].shape, shape[i])\n", + " #assert np.prod(state_dict[key].shape) == np.prod(shape[i])\n", + " start_index = end_index\n", + "\n", + " reverse_top10 = flatten_model(state_dict)\n", + " \n", + " flat = flatten_model(resw_oe)\n", + " for k, v in resw_oe.items():\n", + " # print(k, v.shape, state_dict[k].shape)\n", + " assert np.prod(torch.squeeze(v).shape) == np.prod(state_dict[k].shape)\n", + " print(len(reverse_top10), len(flat))\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 235, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11669504 11669504\n", + "haar 47.135135650634766 124408.8359375\n", + "11669504 11669504\n", + "db1 47.135135650634766 124408.8359375\n", + "11669504 11669504\n", + "sym2 47.135135650634766 124408.8359375\n", + "11669504 11669504\n", + "coif1 47.135135650634766 124408.8359375\n", + "11669504 11669504\n", + "bior1.1 47.135135650634766 124408.8359375\n", + "11669504 11669504\n", + "rbio1.1 47.135135650634766 124408.8359375\n", + "11669504 11669504\n", + "dmey 47.135135650634766 124408.8359375\n", + "11669504 11669504\n", + "bior4.4 47.135135650634766 124408.8359375\n", + "min: tensor(47.1351) haar 0\n" + ] + } + ], + "source": [ + "# wavedecn with axes specified, on dimensions reduced to 2x2, level = 0\n", + "\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "#wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " shape = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " coeffs = []\n", + " to_del = []\n", + " for key, v in resw_oe.items():\n", + " #print(key, v.shape)\n", + " if v.shape == torch.Size([]):\n", + " print(key)\n", + " to_del.append(key)\n", + " continue\n", + " v = torch.squeeze(v).numpy()\n", + " if len(v.shape) > 2:\n", + " #print(v.shape)\n", + " v = v.reshape((v.shape[0], np.prod(v.shape[1:])))\n", + " #print(v.shape)\n", + " coeff = pywt.wavedecn(v, wavelet, level = 0, axes = (0,1))\n", + " #print(coeff[0].shape)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff, axes = (0,1))\n", + " shape.append(array.shape)\n", + " coeffs.append(coeff_slices)\n", + " #print(array.shape)\n", + " flat_array = torch.from_numpy(array).flatten()\n", + " lens.append(len(flat_array))\n", + " to_cat.append(flat_array)\n", + " for k in to_del:\n", + " del resw_oe[k]\n", + " flat_wv = torch.cat(to_cat)\n", + " topk = torch.topk(\n", + " flat_wv.abs(), round(0.1*len(flat_wv)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_wv))\n", + " top10[topk.indices] = flat_wv[topk.indices]\n", + " \n", + " start_index = 0\n", + " state_dict = {}\n", + " for i, key in enumerate(resw_oe):\n", + " end_index = start_index + lens[i]\n", + " #print(start_index, end_index, top10.shape)\n", + " #print(top10)\n", + " crr = top10[start_index:end_index]\n", + " #print(crr.shape)\n", + " og = pywt.array_to_coeffs(crr.reshape(shape[i]), coeffs[i], output_format=\"wavedecn\")\n", + " state_dict[key] = torch.from_numpy(pywt.waverecn(og, wavelet = wavelet, axes = (0,1)))\n", + " # print(state_dict[key].shape, shape[i])\n", + " #assert np.prod(state_dict[key].shape) == np.prod(shape[i])\n", + " start_index = end_index\n", + "\n", + " reverse_top10 = flatten_model(state_dict)\n", + " \n", + " flat = flatten_model(resw_oe)\n", + " for k, v in resw_oe.items():\n", + " # print(k, v.shape, state_dict[k].shape)\n", + " assert np.prod(torch.squeeze(v).shape) == np.prod(state_dict[k].shape)\n", + " print(len(reverse_top10), len(flat))\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 228, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 47.194419860839844 124593.125\n", + "db1 47.194419860839844 124593.125\n", + "sym2 47.194419860839844 124593.125\n", + "coif1 47.194419860839844 124593.125\n", + "bior1.1 47.194419860839844 124593.125\n", + "rbio1.1 47.194419860839844 124593.125\n", + "dmey 47.194419860839844 124593.125\n", + "bior4.4 47.194419860839844 124593.125\n", + "min: tensor(47.1944) haar 0\n" + ] + } + ], + "source": [ + "# wavedecn implementation with axes\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "#wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " shape = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " coeffs = []\n", + " to_del = []\n", + " for key, v in resw.items():\n", + " #print(key, v.shape)\n", + " if v.shape == torch.Size([]):\n", + " print(key)\n", + " to_del.append(key)\n", + " continue\n", + " \n", + " coeff = pywt.wavedecn(torch.squeeze(v).numpy(), wavelet, level = 0, axes = (0,1))\n", + " #print(coeff[0].shape)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff, axes = (0,1))\n", + " shape.append(array.shape)\n", + " coeffs.append(coeff_slices)\n", + " #print(array.shape)\n", + " flat_array = torch.from_numpy(array).flatten()\n", + " lens.append(len(flat_array))\n", + " to_cat.append(flat_array)\n", + " for k in to_del:\n", + " del resw[k]\n", + " flat_wv = torch.cat(to_cat)\n", + " topk = torch.topk(\n", + " flat_wv.abs(), round(0.1*len(flat_wv)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_wv))\n", + " top10[topk.indices] = flat_wv[topk.indices]\n", + " \n", + " start_index = 0\n", + " state_dict = {}\n", + " for i, key in enumerate(resw):\n", + " end_index = start_index + lens[i]\n", + " #print(start_index, end_index, top10.shape)\n", + " #print(top10)\n", + " crr = top10[start_index:end_index]\n", + " #print(crr.shape)\n", + " og = pywt.array_to_coeffs(crr.reshape(shape[i]), coeffs[i], output_format=\"wavedec\")\n", + " state_dict[key] = torch.from_numpy(pywt.waverecn(og, wavelet = wavelet, axes = (0,1)))\n", + " start_index = end_index\n", + "\n", + " reverse_top10 = flatten_model(state_dict)\n", + " flat = flatten_model(resw)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 229, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 47.194419860839844 124593.125\n", + "db1 47.194419860839844 124593.125\n", + "sym2 47.194419860839844 124593.125\n", + "coif1 47.194419860839844 124593.125\n", + "bior1.1 47.194419860839844 124593.125\n", + "rbio1.1 47.194419860839844 124593.125\n", + "dmey 47.194419860839844 124593.125\n", + "bior4.4 47.194419860839844 124593.125\n", + "min: tensor(47.1944) haar 0\n" + ] + } + ], + "source": [ + "# wavedec on flat\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "#wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " shape = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " coeffs = []\n", + " to_del = []\n", + " for key, v in resw.items():\n", + " #print(key, v.shape)\n", + " if v.shape == torch.Size([]):\n", + " print(key)\n", + " to_del.append(key)\n", + " continue\n", + " \n", + " coeff = pywt.wavedec(torch.squeeze(v.flatten()).numpy(), wavelet, level = 0)\n", + " #print(coeff[0].shape)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " shape.append(array.shape)\n", + " coeffs.append(coeff_slices)\n", + " #print(array.shape)\n", + " flat_array = torch.from_numpy(array).flatten()\n", + " lens.append(len(flat_array))\n", + " to_cat.append(flat_array)\n", + " for k in to_del:\n", + " del resw[k]\n", + " flat_wv = torch.cat(to_cat)\n", + " topk = torch.topk(\n", + " flat_wv.abs(), round(0.1*len(flat_wv)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_wv))\n", + " top10[topk.indices] = flat_wv[topk.indices]\n", + " \n", + " start_index = 0\n", + " state_dict = {}\n", + " for i, key in enumerate(resw):\n", + " end_index = start_index + lens[i]\n", + " #print(start_index, end_index, top10.shape)\n", + " #print(top10)\n", + " crr = top10[start_index:end_index]\n", + " #print(crr.shape)\n", + " og = pywt.array_to_coeffs(crr.reshape(shape[i]), coeffs[i], output_format=\"wavedec\")\n", + " state_dict[key] = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " start_index = end_index\n", + "\n", + " reverse_top10 = flatten_model(state_dict)\n", + " flat = flatten_model(resw)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 230, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 42.886417388916016 114614.34375\n", + "db1 42.886417388916016 114614.34375\n", + "sym2 42.55022430419922 113962.6484375\n", + "coif1 42.59132385253906 114232.9609375\n", + "bior1.1 42.886417388916016 114614.34375\n", + "rbio1.1 42.886417388916016 114614.34375\n", + "dmey 42.56193542480469 113790.9296875\n", + "bior4.4 42.609718322753906 114087.71875\n", + "min: tensor(42.5502) sym2 2\n" + ] + } + ], + "source": [ + "# manual layerwise wavelet with level = None\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "#wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " shape = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " coeffs = []\n", + " to_del = []\n", + " for key, v in resw.items():\n", + " #print(key, v.shape)\n", + " if v.shape == torch.Size([]):\n", + " print(key)\n", + " to_del.append(key)\n", + " continue\n", + " \n", + " coeff = pywt.wavedec(torch.squeeze(v.flatten()).numpy(), wavelet, level = None)\n", + " #print(coeff[0].shape)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " shape.append(array.shape)\n", + " coeffs.append(coeff_slices)\n", + " #print(array.shape)\n", + " flat_array = torch.from_numpy(array).flatten()\n", + " lens.append(len(flat_array))\n", + " to_cat.append(flat_array)\n", + " for k in to_del:\n", + " del resw[k]\n", + " flat_wv = torch.cat(to_cat)\n", + " topk = torch.topk(\n", + " flat_wv.abs(), round(0.1*len(flat_wv)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_wv))\n", + " top10[topk.indices] = flat_wv[topk.indices]\n", + " \n", + " start_index = 0\n", + " state_dict = {}\n", + " for i, key in enumerate(resw):\n", + " end_index = start_index + lens[i]\n", + " #print(start_index, end_index, top10.shape)\n", + " #print(top10)\n", + " crr = top10[start_index:end_index]\n", + " #print(crr.shape)\n", + " og = pywt.array_to_coeffs(crr.reshape(shape[i]), coeffs[i], output_format=\"wavedec\")\n", + " state_dict[key] = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " start_index = end_index\n", + "\n", + " reverse_top10 = flatten_model(state_dict)\n", + " flat = flatten_model(resw)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [], + "source": [ + "resw2 = {}\n", + "resw2[\"fc.weight\"] = resw[\"fc.weight\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [], + "source": [ + "resw = resw2" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([1000, 512])" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "resw2[\"fc.weight\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 31.85331916809082 18000.552734375\n", + "db1 31.85331916809082 18000.552734375\n", + "sym2 31.85331916809082 18000.552734375\n", + "coif1 31.85331916809082 18000.552734375\n", + "bior1.1 31.85331916809082 18000.552734375\n", + "rbio1.1 31.85331916809082 18000.552734375\n", + "dmey 31.85331916809082 18000.552734375\n", + "bior4.4 31.85331916809082 18000.552734375\n", + "min: tensor(31.8533) haar 0\n" + ] + } + ], + "source": [ + "# wavedecn implementation with axes\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "#wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " lens = []\n", + " shape = []\n", + " fft_layers = []\n", + " to_cat = []\n", + " coeffs = []\n", + " to_del = []\n", + " for key, v in resw.items():\n", + " #print(key, v.shape)\n", + " if v.shape == torch.Size([]):\n", + " print(key)\n", + " to_del.append(key)\n", + " continue\n", + " \n", + " coeff = pywt.wavedecn(torch.squeeze(v).numpy(), wavelet, level = 0, axes = (0,1))\n", + " #print(coeff[0].shape)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff, axes = (0,1))\n", + " shape.append(array.shape)\n", + " coeffs.append(coeff_slices)\n", + " #print(array.shape)\n", + " flat_array = torch.from_numpy(array).flatten()\n", + " lens.append(len(flat_array))\n", + " to_cat.append(flat_array)\n", + " for k in to_del:\n", + " del resw[k]\n", + " flat_wv = torch.cat(to_cat)\n", + " topk = torch.topk(\n", + " flat_wv.abs(), round(0.1*len(flat_wv)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(flat_wv))\n", + " top10[topk.indices] = flat_wv[topk.indices]\n", + " \n", + " start_index = 0\n", + " state_dict = {}\n", + " for i, key in enumerate(resw):\n", + " end_index = start_index + lens[i]\n", + " #print(start_index, end_index, top10.shape)\n", + " #print(top10)\n", + " crr = top10[start_index:end_index]\n", + " #print(crr.shape)\n", + " og = pywt.array_to_coeffs(crr.reshape(shape[i]), coeffs[i], output_format=\"wavedec\")\n", + " state_dict[key] = torch.from_numpy(pywt.waverecn(og, wavelet = wavelet, axes = (0,1)))\n", + " start_index = end_index\n", + "\n", + " reverse_top10 = flatten_model(state_dict)\n", + " flat = flatten_model(resw)\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [], + "source": [ + "flat = flatten_model(resw)" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [], + "source": [ + "topk_og = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + "top10_og = torch.zeros(len(flat))\n", + "top10_og[topk_og.indices] = flat[topk_og.indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(31.8533)" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(top10_og - flat, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 34.37525939941406 19823.703125\n", + "db1 34.37525939941406 19823.703125\n", + "sym2 34.24169921875 19703.4453125\n", + "coif1 34.238433837890625 19669.91796875\n", + "bior1.1 34.37525939941406 19823.703125\n", + "rbio1.1 34.37525939941406 19823.703125\n", + "dmey 35.10240936279297 20091.73828125\n", + "bior4.4 34.86445999145508 19995.5078125\n", + "min: tensor(34.2384) coif1 3\n" + ] + } + ], + "source": [ + "# wavelet on flattened\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "# wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [], + "source": [ + "not_flat = list(resw.values())[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([1000, 512])" + ] + }, + "execution_count": 87, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "not_flat.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 233, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "haar 31.85331916809082 18000.552734375\n", + "db1 31.85331916809082 18000.552734375\n", + "sym2 31.85331916809082 18000.552734375\n", + "coif1 31.85331916809082 18000.552734375\n", + "bior1.1 31.85331916809082 18000.552734375\n", + "rbio1.1 31.85331916809082 18000.552734375\n", + "dmey 31.85331916809082 18000.552734375\n", + "bior4.4 31.85331916809082 18000.552734375\n", + "min: tensor(31.8533) haar 0\n" + ] + } + ], + "source": [ + "# wavdecn on not flat, with level None\n", + "# working on the random initialization\n", + "wavelets = ['haar', 'db1', 'sym2', 'coif1', 'bior1.1', 'rbio1.1', 'dmey', 'bior4.4'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "# wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " coeff = pywt.wavedecn(not_flat.numpy(), wavelet, level = 0)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " shape = array.shape\n", + " array = array.flatten()\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " top10 = top10.reshape(shape)\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedecn\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverecn(og, wavelet = wavelet))\n", + " err = torch.norm(reverse_top10 - not_flat, 2)\n", + " err1 = torch.norm(reverse_top10 - not_flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "Wavelet create an array of the entire thing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Combination of the best" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "resw2 = {}\n", + "resw2[\"fc.weight\"] = resw[\"fc.weight\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "del resw[\"fc.weight\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "flat = flatten_model(resw)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sym2 38.345680236816406 100879.03125\n", + "min: tensor(38.3457) sym2 0\n" + ] + } + ], + "source": [ + "# Base case on flattened data, with level=4\n", + "# working on the random initialization\n", + "wavelets = ['sym2'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "# wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " coeff = pywt.wavedec(flat.numpy(), wavelet, level = 4)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " #print(coeff_slices) # should be static so we do not need to send them\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedec\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverec(og, wavelet = wavelet))\n", + " err = torch.norm(reverse_top10 - flat, 2)\n", + " err1 = torch.norm(reverse_top10 - flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "r10_1 = reverse_top10" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(43.5638)" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk_og = torch.topk(\n", + " flat.abs(), round(0.1*len(flat)), dim=0, sorted=False\n", + " )\n", + "top10_og1 = torch.zeros(len(flat))\n", + "top10_og1[topk_og.indices] = flat[topk_og.indices]\n", + "torch.norm(top10_og1 - flat, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "not_flat = list(resw2.values())[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sym2 31.85331916809082 18000.552734375\n", + "min: tensor(31.8533) sym2 0\n" + ] + } + ], + "source": [ + "# wavdecn on not flat, with level None\n", + "# working on the random initialization\n", + "wavelets = ['sym2'] # 'gaus1' not supported, 'mexh','morl', 'cgau1', 'shan', 'fbsp', 'cmor'\n", + "# wavelets = pywt.wavelist(kind='discrete', )\n", + "errs = []\n", + "names = []\n", + "for wavelet in wavelets:\n", + " coeff = pywt.wavedecn(not_flat.numpy(), wavelet, level = 0)\n", + " array, coeff_slices = pywt.coeffs_to_array(coeff)\n", + " shape = array.shape\n", + " array = array.flatten()\n", + " topk = torch.topk(\n", + " torch.from_numpy(np.absolute(array)), round(0.1*len(array)), dim=0, sorted=False\n", + " )\n", + " top10 = torch.zeros(len(array))\n", + " top10[topk.indices] = torch.from_numpy(array[topk.indices])\n", + " top10 = top10.reshape(shape)\n", + " og = pywt.array_to_coeffs(top10, coeff_slices, output_format=\"wavedecn\")\n", + " reverse_top10 = torch.from_numpy(pywt.waverecn(og, wavelet = wavelet))\n", + " err = torch.norm(reverse_top10 - not_flat, 2)\n", + " err1 = torch.norm(reverse_top10 - not_flat, 1)\n", + " errs.append(err)\n", + " names.append(wavelet)\n", + " print(wavelet, err.item(), err1.item())\n", + "ind = np.argmin(errs)\n", + "print(\"min: \", errs[ind], names[ind], ind)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "r10 = torch.cat([r10_1, reverse_top10.flatten()])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(50.8493)" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "topk_og = torch.topk(\n", + " not_flat.flatten().abs(), round(0.1*len(not_flat.flatten())), dim=0, sorted=False\n", + " )\n", + "top10_og2 = torch.zeros(len(not_flat.flatten()))\n", + "top10_og2[topk_og.indices] = flat[topk_og.indices]\n", + "torch.norm(top10_og2 - not_flat.flatten(), 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "r10_og = torch.cat([top10_og1, top10_og2])" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "models = torchvision.models.resnet18(True).state_dict()" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "models = {k:v for k,v in models.items() if \"bn1.\" not in k}\n", + "models = {k:v for k,v in models.items() if \"bn2.\" not in k}\n", + "models = {k:v for k,v in models.items() if len(v.shape) >1}" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "flat= flatten_model(models)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(49.8481)" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(r10 - flat, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(66.9528)" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.norm(r10_og - flat, 2) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "996934296aa9d79be6c3d800a38d8fdb7dfa8fe7bb07df178f1397cde2cb8742" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/random files/plotting_from_csv.py b/random files/plotting_from_csv.py new file mode 100644 index 0000000000000000000000000000000000000000..07f89a0e26b9881c1f3293be4fb88d806d35eab0 --- /dev/null +++ b/random files/plotting_from_csv.py @@ -0,0 +1,173 @@ +import distutils +import json +import os +import sys + +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt + + +def plot(x_axis, means, stdevs, pos, nb_plots, title, label, loc, xlabel): + cmap = plt.get_cmap("gist_rainbow") + plt.title(title) + plt.xlabel(xlabel) + y_axis = list(means) + err = list(stdevs) + print("label:", label) + print("color: ", cmap(1 / nb_plots * pos)) + plt.errorbar( + list(x_axis), y_axis, yerr=err, label=label, color=cmap(1 / nb_plots * pos) + ) + plt.legend(loc=loc) + + +def plot_results(path, epochs, global_epochs=True): + print(path, epochs, global_epochs, type(global_epochs)) + global_epochs = bool(distutils.util.strtobool(global_epochs)) + epochs = int(epochs) + folders = os.listdir(path) + folders.sort() + print("Reading folders from: ", path) + print("Folders: ", folders) + bytes_means, bytes_stdevs = {}, {} + meta_means, meta_stdevs = {}, {} + data_means, data_stdevs = {}, {} + + files = os.listdir(path) + files = [f for f in files if f.endswith(".csv")] + train_loss = sorted([f for f in files if f.startswith("train_loss")]) + test_acc = sorted([f for f in files if f.startswith("test_acc")]) + test_loss = sorted([f for f in files if f.startswith("test_loss")]) + max_losses = [] + for i, f in enumerate(train_loss): + filepath = os.path.join(path, f) + with open(filepath, "r") as inf: + results_csv = pd.read_csv(inf) + # Plot Training loss + plt.figure(1) + if global_epochs: + means = results_csv["mean"].to_numpy() + stdevs = results_csv["std"].to_numpy() + means = means[:epochs] + stdevs = stdevs[:epochs] + x_axis = list(np.arange(0, len(means), 1)) + x_label = "global epochs" + else: + results_cr = results_csv[results_csv.rounds <= epochs] + means = results_cr["mean"].to_numpy() + stdevs = results_cr["std"].to_numpy() + x_axis = results_cr["rounds"].to_numpy() + x_label = "communication rounds" + max_losses.append(np.max(means)) + + plot( + x_axis, + means, + stdevs, + i, + len(train_loss), + "Training Loss", + f[len("train_loss") + 1 : -len(":2022-03-24T17:54.csv")], + "upper right", + x_label, + ) + + max_tlosses = [] + for i, f in enumerate(test_loss): + filepath = os.path.join(path, f) + with open(filepath, "r") as inf: + results_csv = pd.read_csv(inf) + if global_epochs: + means = results_csv["mean"].to_numpy() + stdevs = results_csv["std"].to_numpy() + means = means[:epochs] + stdevs = stdevs[:epochs] + x_axis = list(np.arange(0, len(means), 1)) + x_label = "global epochs" + else: + results_cr = results_csv[results_csv.rounds <= epochs] + means = results_cr["mean"].to_numpy() + stdevs = results_cr["std"].to_numpy() + x_axis = results_cr["rounds"].to_numpy() + x_label = "communication rounds" + print("x axis:", x_axis) + max_tlosses.append(np.max(means)) + # Plot Testing loss + plt.figure(2) + plot( + x_axis, + means, + stdevs, + i, + len(test_loss), + "Testing Loss", + f[len("test_loss") + 1 : -len(":2022-03-24T17:54.csv")], + "upper right", + x_label, + ) + + max_taccs = [] + for i, f in enumerate(test_acc): + filepath = os.path.join(path, f) + with open(filepath, "r") as inf: + results_csv = pd.read_csv(inf) + if global_epochs: + means = results_csv["mean"].to_numpy() + stdevs = results_csv["std"].to_numpy() + means = means[:epochs] + stdevs = stdevs[:epochs] + x_axis = list(np.arange(0, len(means), 1)) + x_label = "global epochs" + else: + results_cr = results_csv[results_csv.rounds <= epochs] + means = results_cr["mean"].to_numpy() + stdevs = results_cr["std"].to_numpy() + x_axis = results_cr["rounds"].to_numpy() + x_label = "communication rounds" + max_taccs.append(np.max(means)) + # Plot Testing Accuracy + plt.figure(3) + plot( + x_axis, + means, + stdevs, + i, + len(test_acc), + "Testing Accuracy", + f[len("test_acc") + 1 : -len(":2022-03-24T17:54.csv")], + "lower right", + x_label, + ) + + names_loss = [ + f[len("train_loss") + 1 : -len(":2022-03-24T17:54.csv")] for f in train_loss + ] + names_acc = [ + f[len("test_acc") + 1 : -len(":2022-03-24T17:54.csv")] for f in test_acc + ] + print(names_loss) + print(names_acc) + pf = pd.DataFrame( + { + "test_accuracy": max_taccs, + "test_losses": max_tlosses, + "train_losses": max_losses, + }, + names_loss, + ) + pf = pf.sort_values(["test_accuracy"], 0, ascending=False) + pf.to_csv(os.path.join(path, "best_results.csv")) + + plt.figure(1) + plt.savefig(os.path.join(path, "ge_train_loss.png"), dpi=300) + plt.figure(2) + plt.savefig(os.path.join(path, "ge_test_loss.png"), dpi=300) + plt.figure(3) + plt.savefig(os.path.join(path, "ge_test_acc.png"), dpi=300) + + +if __name__ == "__main__": + assert len(sys.argv) == 4 + print(sys.argv[1], sys.argv[2], sys.argv[3]) + plot_results(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/random files/reddit.ipynb b/random files/reddit.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..b3496c608e081082273e686f34f8521e6eef7c8d --- /dev/null +++ b/random files/reddit.ipynb @@ -0,0 +1,960 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZMZYcW3itMzT", + "outputId": "f2970f7e-cf26-4a67-e8d3-29bcd1a11775" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2VftlLfttdT8", + "outputId": "48b47fdc-853b-4711-ae95-8c0e64510615" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "ft7BMl1LyWP6" + }, + "outputs": [], + "source": [ + "from torch import nn\n", + "import torch\n", + "import os\n", + "import json\n", + "import pickle\n", + "import numpy as np\n", + "import pywt\n", + "import collections\n", + "from decentralizepy.datasets.Partitioner import DataPartitioner\n", + "from collections import defaultdict\n", + "train_dir = \"/home/jeffrey/Downloads/reddit/per_user_data/train\"\n", + "test_dir=\"/home/jeffrey/Downloads/reddit/new_small_data/test\"\n", + "my_train_data = {\"x\": [], \"y\": []}" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def test_reddit(tmpdir):\n", + " mapping = Linear(6, 16)\n", + " reddit = Reddit(0,0,mapping,\n", + " n_procs = 96,\n", + " train_dir = \"/home/jeffrey/Downloads/reddit/per_user_data/train\",\n", + " test_dir=\"/home/jeffrey/Downloads/reddit/new_small_data/test\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<torch._C.Generator at 0x7fc21c0c6d30>" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.manual_seed(13)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "hi0N5rB5xBWn" + }, + "outputs": [], + "source": [ + "if torch.cuda.is_available():\n", + " device = \"cuda\"\n", + "else:\n", + " device = \"cpu\"" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "6lO3uYsmxNYz", + "outputId": "b170b610-f21e-465d-fcd6-b7e6989e73e5" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'cpu'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "device" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CNN Model Training <a class=\"anchor\" id=\"train\"></a>" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def _load_vocab(VOCABULARY_PATH):\n", + " vocab_file = pickle.load(open(VOCABULARY_PATH, 'rb'))\n", + " vocab = collections.defaultdict(lambda: vocab_file['unk_symbol'])\n", + " vocab.update(vocab_file['vocab'])\n", + "\n", + " return vocab, vocab_file['size'], vocab_file['unk_symbol'], vocab_file['pad_symbol']" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "vocab_path = os.path.join(train_dir, '../../vocab/reddit_vocab.pck')\n", + "vocab, vocab_size, unk_symbol, pad_symbol = _load_vocab(vocab_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def prepare_data(data):\n", + " data_x = data['x']\n", + " data_y = data['y']\n", + "\n", + " # flatten lists\n", + " def flatten_lists(data_x_by_comment, data_y_by_comment):\n", + " data_x_by_seq, data_y_by_seq = [], []\n", + " for c, l in zip(data_x_by_comment, data_y_by_comment):\n", + " data_x_by_seq.extend(c)\n", + " data_y_by_seq.extend(l['target_tokens'])\n", + "\n", + " return data_x_by_seq, data_y_by_seq\n", + "\n", + " data_x, data_y = flatten_lists(data_x, data_y)\n", + "\n", + " data_x_processed = process_x(data_x)\n", + " data_y_processed = process_y(data_y)\n", + "\n", + " filtered_x, filtered_y = [], []\n", + " for i in range(len(data_x_processed)):\n", + " if (np.sum(data_y_processed[i]) != 0):\n", + " filtered_x.append(data_x_processed[i])\n", + " filtered_y.append(data_y_processed[i])\n", + "\n", + " return (filtered_x, filtered_y)\n", + "\n", + "def _tokens_to_ids(raw_batch):\n", + " def tokens_to_word_ids(tokens, word2id):\n", + " return [word2id[word] for word in tokens]\n", + "\n", + " to_ret = [tokens_to_word_ids(seq, vocab) for seq in raw_batch]\n", + " return np.array(to_ret)\n", + "\n", + "def process_x(raw_x_batch):\n", + " \"\"\"\n", + " copied from https://gitlab.epfl.ch/sacs/efficient-federated-learning/-/blob/master/grad_guessing/data_utils.py\n", + " Parameters\n", + " ----------\n", + " raw_x_batch\n", + "\n", + " Returns\n", + " -------\n", + "\n", + " \"\"\"\n", + " tokens = _tokens_to_ids([s for s in raw_x_batch])\n", + " return tokens\n", + "\n", + "def process_y( raw_y_batch):\n", + " \"\"\"\n", + " copied from https://gitlab.epfl.ch/sacs/efficient-federated-learning/-/blob/master/grad_guessing/data_utils.py\n", + " Parameters\n", + " ----------\n", + " raw_y_batch\n", + "\n", + " Returns\n", + " -------\n", + "\n", + " \"\"\"\n", + " tokens = _tokens_to_ids([s for s in raw_y_batch])\n", + "\n", + " def getNextWord(token_ids):\n", + " n = len(token_ids)\n", + " for i in range(n):\n", + " # gets the word at the end of the phrase that should be predicted\n", + " # that is the last token that is not a pad.\n", + " if (token_ids[n - i - 1] != pad_symbol):\n", + " return token_ids[n - i - 1]\n", + " return pad_symbol\n", + "\n", + " return [getNextWord(t) for t in tokens]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "9LpgzEw1s-xo" + }, + "outputs": [], + "source": [ + "def __read_file__(file_path):\n", + " with open(file_path, \"r\") as inf:\n", + " client_data = json.load(inf)\n", + " return (\n", + " client_data[\"users\"],\n", + " client_data[\"num_samples\"],\n", + " client_data[\"user_data\"],\n", + " )\n", + "\n", + "def __read_dir__(data_dir):\n", + " users = []\n", + " num_samples = []\n", + " data = defaultdict(lambda: None)\n", + "\n", + " files = os.listdir(data_dir)\n", + " files = [f for f in files if f.endswith(\".json\")]\n", + " for f in files:\n", + " file_path = os.path.join(data_dir, f)\n", + " u, n, d = __read_file__(file_path)\n", + " users.extend(u)\n", + " num_samples.extend(n)\n", + " data.update(d)\n", + " return users, num_samples, data" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "sizes= None\n", + "n_procs = 1 # why can I access n_procs but not train_x in the load_trianset function\n", + "train_x = []\n", + "train_y = []" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "QBu1kiw8s-xr" + }, + "outputs": [], + "source": [ + "def load_trainset():\n", + " files = os.listdir(train_dir)\n", + " files = [f for f in files if f.endswith(\".json\")]\n", + " files.sort()\n", + " c_len = len(files)\n", + " sizes = None\n", + " print(n_procs)\n", + " if sizes == None: # Equal distribution of data among processes\n", + " e = c_len // n_procs\n", + " frac = e / c_len\n", + " sizes = [frac] * n_procs\n", + " sizes[-1] += 1.0 - frac * n_procs\n", + " uid = 0\n", + " my_clients = DataPartitioner(files, sizes).use(0)\n", + " my_clients = list(my_clients)\n", + " my_train_data = {\"x\": [], \"y\": []}\n", + " #self.clients = []\n", + " num_samples = []\n", + " for i in range(my_clients.__len__()):\n", + " cur_file = my_clients.__getitem__(i)\n", + "\n", + " clients, _, train_data = __read_file__(\n", + " os.path.join(train_dir, cur_file)\n", + " )\n", + " for cur_client in clients:\n", + " #self.clients.append(cur_client)\n", + " processed_x, processed_y = prepare_data(train_data[cur_client])\n", + " # processed_x is an list of fixed size word id arrays that represent a phrase\n", + " # processed_y is a list of word ids that each represent the next word of a phrase\n", + " my_train_data[\"x\"].extend(processed_x)\n", + " my_train_data[\"y\"].extend(processed_y)\n", + " num_samples.append(len(processed_y))\n", + " # turns the list of lists into a single list\n", + " train_y = np.array(my_train_data[\"y\"], dtype=np.dtype(\"int64\")).reshape(-1)\n", + " train_x = np.array(my_train_data[\"x\"], dtype=np.dtype(\"int64\"))#.reshape(-1)\n", + " print(len(train_x), len(train_y))\n", + " print(\"train_x.shape:\", str(train_x.shape))\n", + " print(\"train_y.shape:\", str(train_y.shape))\n", + " assert train_x.shape[0] == train_y.shape[0]\n", + " assert train_x.shape[0] > 0\n", + " return train_x, train_y" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "test_x = []\n", + "test_y = []" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def load_testset():\n", + " \"\"\"\n", + " Loads the testing set.\n", + "\n", + " \"\"\"\n", + " _, _, d = __read_dir__(test_dir)\n", + " test_x = []\n", + " test_y = []\n", + " for test_data in d.values():\n", + " processed_x, processed_y = prepare_data(test_data)\n", + " # processed_x is an list of fixed size word id arrays that represent a phrase\n", + " # processed_y is a list of word ids that each represent the next word of a phrase\n", + " test_x.extend(processed_x)\n", + " test_y.extend(processed_y)\n", + " test_y = np.array(test_y, dtype=np.dtype(\"int64\")).reshape(-1)\n", + " test_x = np.array(test_x, dtype=np.dtype(\"int64\"))\n", + " print(test_x)\n", + " print(len(test_x), len(test_x))\n", + " print(\"test_x.shape:\", str(test_x.shape))\n", + " print(\"test_y.shape:\", str(test_y.shape))\n", + " assert test_x.shape[0] == test_y.shape[0]\n", + " assert test_x.shape[0] > 0\n", + " return test_x, test_y" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "70642 70642\n", + "train_x.shape: (70642, 10)\n", + "train_y.shape: (70642,)\n" + ] + } + ], + "source": [ + "train_x, train_y = load_trainset()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 5, 953, 1341, ..., 834, 298, 1288],\n", + " [ 436, 1060, 6, ..., 0, 0, 0],\n", + " [ 5, 7948, 1, ..., 7654, 1, 1],\n", + " ...,\n", + " [ 67, 433, 1465, ..., 0, 0, 0],\n", + " [ 5, 13, 119, ..., 12, 17, 13],\n", + " [ 324, 324, 324, ..., 0, 0, 0]])" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_x" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 5 90 1 ... 6 0 0]\n", + " [ 5 13 1121 ... 75 26 110]\n", + " [ 27 13 1510 ... 13 4813 21]\n", + " ...\n", + " [ 5 1784 1 ... 1 1026 4]\n", + " [1784 4734 489 ... 1 7 3190]\n", + " [ 761 75 1 ... 0 0 0]]\n", + "24961 24961\n", + "test_x.shape: (24961, 10)\n", + "test_y.shape: (24961,)\n" + ] + } + ], + "source": [ + "test_x, test_y = load_testset()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 5, 90, 1, ..., 6, 0, 0],\n", + " [ 5, 13, 1121, ..., 75, 26, 110],\n", + " [ 27, 13, 1510, ..., 13, 4813, 21],\n", + " ...,\n", + " [ 5, 1784, 1, ..., 1, 1026, 4],\n", + " [1784, 4734, 489, ..., 1, 7, 3190],\n", + " [ 761, 75, 1, ..., 0, 0, 0]])" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "id": "mAEASHr2s-x1" + }, + "outputs": [], + "source": [ + "VOCAB_LEN = 9999 \n", + "SEQ_LEN = 10\n", + "EMBEDDING_DIM = 200" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "from decentralizepy.models.Model import Model\n", + "import torch.nn.functional as F" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "id": "GPyZ2C8ws-x9" + }, + "outputs": [], + "source": [ + "class RNN(Model):\n", + " \"\"\"\n", + " Class for a RNN Model for Reddit\n", + "\n", + " \"\"\"\n", + "\n", + " def __init__(self):\n", + " \"\"\"\n", + " Constructor. Instantiates the RNN Model to predict the next word of a sequence of word.\n", + " Based on the TensorFlow model found here: https://gitlab.epfl.ch/sacs/efficient-federated-learning/-/blob/master/grad_guessing/data_utils.py\n", + " \"\"\"\n", + " super().__init__()\n", + "\n", + " # input_length does not exist\n", + " self.embedding = nn.Embedding(VOCAB_LEN, EMBEDDING_DIM, padding_idx=0)\n", + " self.rnn_cells = nn.LSTM(EMBEDDING_DIM, 256, batch_first=True, num_layers=2) # not sure about the first argument input_size\n", + " # activation function is added in the forward pass\n", + " # Note: the tensorflow implementation did not use any activation function in this step?\n", + " # should I use one.\n", + " self.l1 = nn.Linear(256, 128)\n", + " # the tf model used sofmax activation here\n", + " self.l2 = nn.Linear(128, VOCAB_LEN)\n", + "\n", + " def forward(self, x):\n", + " \"\"\"\n", + " Forward pass of the model\n", + "\n", + " Parameters\n", + " ----------\n", + " x : torch.tensor\n", + " The input torch tensor\n", + "\n", + " Returns\n", + " -------\n", + " torch.tensor\n", + " The output torch tensor\n", + "\n", + " \"\"\"\n", + " x = self.embedding(x)\n", + " #print(x.shape)\n", + " x = self.rnn_cells(x)\n", + " #print(x[0].shape)\n", + " #print(x[1][0].shape)\n", + " last_layer_output = x[1][0][1,...]\n", + " #print(\"last_layer:\", last_layer_output.shape)\n", + " x = F.relu(self.l1(x[1][0][1,...]))\n", + " #print(x.shape)\n", + " x = self.l2(x)\n", + " # softmax is applied by the CrossEntropyLoss used during training\n", + " return x\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "bCgW8ClBs-x_" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "id": "oBGwcwZks-yA" + }, + "outputs": [], + "source": [ + "import os\n", + "from torch.utils.data import Dataset\n", + "\n", + "class RedditDataset(Dataset):\n", + " def __init__(self, training, transform=None, target_transform=None):\n", + " if training:\n", + " #with open(train_dir+\"femnist.pkl\", \"rb\") as f:\n", + " #train = pickle.load(f)\n", + " self.data = train_x\n", + " self.label = train_y\n", + " else: \n", + " #with open(train_dir+\"femnist_test.pkl\", \"rb\") as f:\n", + " #test = pickle.load(f)\n", + " self.data = test_x\n", + " self.label = test_y\n", + " self.transform = transform\n", + " self.target_transform = target_transform\n", + "\n", + " def __len__(self):\n", + " return len(self.label)\n", + "\n", + " def __getitem__(self, idx):\n", + " return self.data[idx], self.label[idx]" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "U3boC_N4s-yC" + }, + "outputs": [], + "source": [ + "from torch.utils.data import DataLoader" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "sJsrQXkEs-yD" + }, + "outputs": [], + "source": [ + "trainset = RedditDataset(True)\n", + "testset = RedditDataset(False)\n", + "\n", + "train_dataloader = DataLoader(trainset, batch_size=16, shuffle=True)\n", + "test_dataloader = DataLoader(testset, batch_size=128, shuffle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4416" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(train_dataloader)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "70656" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "552*128" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "id": "e65Izyv0s-yE" + }, + "outputs": [], + "source": [ + "lr = 0.1\n", + "model = RNN().to(device)\n", + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.SGD(model.parameters(), lr=lr)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "eqOXilqMs-yF", + "outputId": "06799a3b-983b-4f51-a7bd-a901c041bd05" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 4.976342 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 26.0%, Avg loss: 4.879616 \n", + "\n", + "loss: 4.882441 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 28.8%, Avg loss: 4.710636 \n", + "\n", + "loss: 4.665762 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 30.0%, Avg loss: 4.597566 \n", + "\n", + "loss: 4.593148 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 31.8%, Avg loss: 4.533113 \n", + "\n", + "loss: 4.442960 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 32.2%, Avg loss: 4.463360 \n", + "\n", + "loss: 4.288299 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 30.8%, Avg loss: 4.559918 \n", + "\n", + "loss: 4.191413 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 30.7%, Avg loss: 4.568339 \n", + "\n", + "loss: 3.979227 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 31.4%, Avg loss: 4.590676 \n", + "\n", + "loss: 3.857259 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 30.8%, Avg loss: 4.667198 \n", + "\n", + "loss: 3.840112 [ 8832/70642]\n", + "epoch:\n", + "Test Error: \n", + " Accuracy: 30.9%, Avg loss: 4.786180 \n", + "\n" + ] + } + ], + "source": [ + "stats = {\"train\": [], \"test\":[]}\n", + "loss_mvg = None\n", + "for e in range(10):\n", + " #training\n", + " batch = 0\n", + " for X, y in train_dataloader:\n", + " #print(\"grad: \"+str(model.conv1.bias.grad))\n", + " #old = model.conv1.bias.clone()\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " #print(len(label))\n", + " size = len(train_dataloader.dataset)\n", + " model.train()\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " #print(X.shape, y.shape) is torch.Size([128, 10]) torch.Size([128])\n", + " loss = loss_fn(pred, y)\n", + " # Backpropagation\n", + " loss.backward()\n", + " #print(\"grad2: \"+str(model.conv1.bias.grad))\n", + " optimizer.step()\n", + " model.zero_grad()\n", + " #optimizer.zero_grad()\n", + " \n", + " #resetting the optimizer\n", + " # optimizer.load_state_dict(model.state_dict())\n", + " vals = optimizer.state.values()\n", + " #print(optimizer.state.values())\n", + " if not loss_mvg:\n", + " loss_mvg = loss.item()\n", + " else:\n", + " loss_mvg = 0.99*loss_mvg + 0.01*loss.item()\n", + " \n", + " batch += 1\n", + " \n", + " loss, current = loss.item(), batch * len(X)\n", + " print(f\"loss: {loss_mvg:>7f} [{current:>5d}/{size:>5d}]\")\n", + " stats[\"train\"].append([batch, e*size + current, loss])\n", + "\n", + "\n", + " #testing\n", + " size = len(test_dataloader.dataset)\n", + " num_batches = len(test_dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in test_dataloader:\n", + " X = X.to(device)\n", + " y = y.to(device)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(\"epoch:\")\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n", + " stats[\"test\"].append([e, test_loss, 100*correct])\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "128 0.001: Accuracy: 32.3%, Avg loss: 4.716327 \n", + "64 0.001: Accuracy: 32.6%, Avg loss: 4.723278 " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "4P-VA0vcs-yH" + }, + "outputs": [], + "source": [ + "with open(train_dir+\"/results:128:\"+str(lr)+\".pkl\", \"wb\") as f:\n", + " pickle.dump(stats, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "641-b_VCvT2b", + "outputId": "cced38ab-5c04-45b2-faf4-e73327126159" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "F_OKqiiHs-yJ", + "outputId": "65786b88-05f4-42fa-a851-03397ef4457a" + }, + "outputs": [], + "source": [ + "lrs = [0.1, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00001]\n", + "for l in lrs:\n", + " with open(train_dir+\"/results:128:\"+str(l)+\".pkl\", \"rb\") as f:\n", + " res = pickle.load(f)\n", + " print(str(l)+\": \" + str(np.amax(res[\"test\"], axis=0)))#+ str(np.max(res[\"test\"]))\n", + " # print(str(l)+\": \" + str(res[\"test\"]))\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rADw-XkfKjOo", + "outputId": "06c54a2c-f7c2-4610-f879-3e1c2f98543f" + }, + "outputs": [], + "source": [ + "lrs = [0.1, 0.01, 0.005, 0.001, 0.0005, 0.0001, 0.00001]\n", + "for l in lrs:\n", + " with open(train_dir+\"/results:128:\"+str(l)+\".pkl\", \"rb\") as f:\n", + " res = pickle.load(f)\n", + " # print(str(l)+\": \" + str(np.amax(res[\"test\"], axis=0)))#+ str(np.max(res[\"test\"]))\n", + " print(str(l)+\": \" + str(res[\"test\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HGpNYzG_s-yJ", + "outputId": "783622a5-249f-4dd8-d242-fc6dfa47443c" + }, + "outputs": [], + "source": [ + "import torch\n", + "resnet = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uZFgT6wss-yL", + "outputId": "10f8fc51-abb7-4c2b-f608-85229f3de29d", + "tags": [] + }, + "outputs": [], + "source": [ + "total = 0\n", + "for i in resnet.state_dict().values():\n", + " total += i.flatten().size(dim=0)\n", + "print(total)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizer analysis <a class=\"anchor\" id=\"optim\"></a>" + ] + } + ], + "metadata": { + "colab": { + "name": "learningrate.ipynb", + "provenance": [] + }, + "interpreter": { + "hash": "996934296aa9d79be6c3d800a38d8fdb7dfa8fe7bb07df178f1397cde2cb8742" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/random files/test_elias.py b/random files/test_elias.py new file mode 100644 index 0000000000000000000000000000000000000000..10366741cc8078665972c00c8eaf86d17ed81816 --- /dev/null +++ b/random files/test_elias.py @@ -0,0 +1,177 @@ +import numpy as np +import time +import os, random, pickle, lzma, leb128, lz4.frame +import uvarint + +# arr = np.random.poisson(3, 500000) #np.random.randint(1, 20, 500000, dtype=np.int32) +# arr=arr.astype(np.int32) +# print("got the array") +# t5 = time.time() +# +# +# lzfour= lz4.frame.compress(arr) +# +# p = pickle.dumps(lzfour) +# print(len(p), len(lzfour)) +# t6 = time.time() +# +# p = pickle.dumps(p) +# +# t7 = time.time() +# print(t6 -t5, t7 -t5) +# +# # elias implementation: taken from this stack overflow post: +# # https://stackoverflow.com/questions/62843156/python-fast-compression-of-large-amount-of-numbers-with-elias-gamma +# def encode(a): +# a = a.view(f'u{a.itemsize}') +# l = np.log2(a).astype('u1') +# L = ((l<<1)+1).cumsum() +# print("L,", L, len(L)) +# out = np.zeros(L[-1] + np.array([64], dtype = "u1")[0], 'u1') +# print("lmax", l.max()+1) +# for i in range(l.max()+1): +# out[L-i-1] += (a>>i)&1 +# print("out:", out, out[-10:]) +# s = np.array([out.size], dtype=np.int64) +# +# print(s) +# size = np.ndarray(8, dtype='u1', buffer=s.data) +# print("size:", size) +# # out[-8:] = size +# ss = s[0] +# # for i in range(64): +# # out[int(L[-1] + 63 - i)] += (ss>>i)&1 +# print("out", out, out[-68:]) +# +# # out.data.contiguous +# packed = np.packbits(out) +# packed[-8:] = size +# print("packed:", packed[-10:]) +# print("out", out, out[-68:]) +# return packed, out.size +# +# def decode(b,n): +# print(b,) +# n_arr = b[-8:] +# print("n_arr:", n_arr) +# n = np.ndarray(1, dtype=np.int64, buffer=n_arr.data)[0] +# print("n:", n) +# b = b[:-8] +# b = np.unpackbits(b,count=n).view(bool) +# s = b.nonzero()[0] +# s = (s<<1).repeat(np.diff(s,prepend=-1)) +# s -= np.arange(-1,len(s)-1) +# s = s.tolist() # list has faster __getitem__ +# ns = len(s) +# def gen(): +# idx = 0 +# yield idx +# while idx < ns: +# idx = s[idx] +# yield idx +# offs = np.fromiter(gen(),int) +# sz = np.diff(offs)>>1 +# mx = sz.max()+1 +# out = np.zeros(offs.size-1,int) +# for i in range(mx): +# out[b[offs[1:]-i-1] & (sz>=i)] += 1<<i +# return out +# +# arr = np.random.poisson(3, 500000) + 1 # elias does not work on 0s # .frame.decompress +# arr= arr.astype(np.int64) +# print("arr:", arr) +# +# +# # t0 = time.time() +# # p = pickle.dumps(arr) +# # t1 = time.time() +# # +# # z = lzma.compress(arr) +# # +# # t2 = time.time() +# # +# # # From https://stackoverflow.com/questions/68968796/variable-length-integer-encoding +# # leb = b''.join(map(leb128.LEB128U.encode, arr)) +# # t3 = time.time() +# # +# # uvar = b''.join(map(uvarint.encode, arr)) +# t4 = time.time() +# +# elias, n = encode(arr) +# +# t5 = time.time() +# # +# # lzfour= lz4.frame.compress(arr.tobytes("C")) +# # +# # t6 = time.time() +# +# # print(elias) +# # print(n) +# # print(elias.size) +# # print(elias.itemsize) +# # print("array size'd:", f'{ arr.size * arr.itemsize:,}') +# # print("pickle'd:", f'{len(p):,}') +# # print("lzma'd:", f'{len(z):,}') +# # print("leb128'd:", f'{len(leb):,}') +# # print("uvarint'd:", f'{len(leb):,}') +# # print("elias'd:", f'{elias.size:,}') +# # print("elias'd:", f'{len(elias):,}') +# # print("elias'd:", f'{len(pickle.dumps(elias)):,}') +# # print("lz4'd:", f'{len(lzfour):,}') +# # print(f"pickle: {t1-t0:.5f}s, lzma: {t2-t1:.5f}s, leb128 {t3-t2:.5f}s, uvarint: {t4-t3:.5f}s, elias: {t5-t4:.5f}s, lz4: {t6-t5:.5f}s") +# +# +# +# # decode +# d0 = time.time() +# +# arr_dec = decode(elias, n) +# print(arr.dtype, arr_dec.dtype) +# print(len(arr) , len(arr_dec)) +# assert len(arr) == len(arr_dec) +# assert (arr == arr_dec).all() +# +# d1 = time.time() +# +# # arr_dec = lz4.frame.decompress(lzfour) +# # arr_dec = np.frombuffer(arr_dec, dtype=np.int32) +# d2 = time.time() +# # print(arr_dec) +# +# print(d1 -d0, d2 - d1) + + +from decentralizepy.compression.Elias import Elias + +arr = np.random.poisson(30, 50000) + 1 # elias does not work on 0s # .frame.decompress +arr= arr.astype(np.int32) +arr = np.cumsum(arr).astype(np.int32) +print("arr:", arr[:3], arr[-3:]) + +#print("Elias of framework:", arr, np.diff(arr), len(np.diff(arr))) +eliaso = Elias() +t1 = time.time() +comp = eliaso.compress(arr) +t2 = time.time() +print("size:", comp.dtype, len(comp), len(pickle.dumps(arr)), len(pickle.dumps(comp))) +arr_dec = eliaso.decompress(comp) +t3= time.time() +print(t2-t1, t3-t2, t3-t1) +print("arr_dec:", arr_dec[:3], arr_dec[-3:]) +print(arr.dtype, arr_dec.dtype) +print(len(arr) , len(arr_dec)) +assert len(arr) == len(arr_dec) +assert (arr == arr_dec).all() + + +arr = np.array([0,1,2,8]) + +comp = eliaso.compress(arr) +arr_dec = eliaso.decompress(comp) +print("test for fix", arr, arr_dec) +print(arr_dec) +print(arr.dtype, arr_dec.dtype) +print(len(arr) , len(arr_dec)) +assert len(arr) == len(arr_dec) +assert (arr == arr_dec).all() + diff --git a/random files/testing_time_offset_dup.py b/random files/testing_time_offset_dup.py new file mode 100644 index 0000000000000000000000000000000000000000..6f85c323acd09410bcedcec8cc3d45e313e44dc7 --- /dev/null +++ b/random files/testing_time_offset_dup.py @@ -0,0 +1,25 @@ +import time + + +print(time.time()) + +print(int(time.time())) + +intervall = 60*5 # NEW Batch of ports avter 5 minutes + +seconds = int(time.time()) // intervall + + + +# we reset after 200 mins + +port_offset_factor = seconds % 40 + +in_day = 40 +ports = 400 +breath = in_day * ports + +offset = port_offset_factor * ports +print(intervall, seconds, port_offset_factor, offset, seconds % in_day, breath) + +# There are 65535 ports in tcp diff --git a/random files/top10_Histogram.png b/random files/top10_Histogram.png new file mode 100644 index 0000000000000000000000000000000000000000..a18d55c04ffaa7dea45dedb550930a1ab38eb57b Binary files /dev/null and b/random files/top10_Histogram.png differ diff --git a/random files/wavelet_bad.png b/random files/wavelet_bad.png new file mode 100644 index 0000000000000000000000000000000000000000..91693c68727f7e096793307f3be0a1a7af87675f Binary files /dev/null and b/random files/wavelet_bad.png differ diff --git a/random files/wavelet_bad_approx.png b/random files/wavelet_bad_approx.png new file mode 100644 index 0000000000000000000000000000000000000000..093529b6ead27ab067bc452ee474f286c1e27ef2 Binary files /dev/null and b/random files/wavelet_bad_approx.png differ diff --git a/random files/wavelet_bad_approx_good.png b/random files/wavelet_bad_approx_good.png new file mode 100644 index 0000000000000000000000000000000000000000..408957a1593494209dafcd7e8d6232de5a52fbba Binary files /dev/null and b/random files/wavelet_bad_approx_good.png differ diff --git a/random files/wavelet_bad_approx_partial.png b/random files/wavelet_bad_approx_partial.png new file mode 100644 index 0000000000000000000000000000000000000000..d2791df7ccdbbdc3214ca9969d8ec99754559010 Binary files /dev/null and b/random files/wavelet_bad_approx_partial.png differ diff --git a/random files/wavelet_good.png b/random files/wavelet_good.png new file mode 100644 index 0000000000000000000000000000000000000000..408957a1593494209dafcd7e8d6232de5a52fbba Binary files /dev/null and b/random files/wavelet_good.png differ diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/decentralizepy/compression/__init__.py b/src/decentralizepy/compression/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391