diff --git a/code/nnv/examples/NN/Fair/adult_fair_data.mat b/code/nnv/examples/NN/Fair/adult_fair_data.mat deleted file mode 100644 index 7099e0b5da..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_fair_data.mat and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_fairify2_data.mat b/code/nnv/examples/NN/Fair/adult_fairify2_data.mat deleted file mode 100644 index 99dc74fb1d..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_fairify2_data.mat and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_fairify_data.mat b/code/nnv/examples/NN/Fair/adult_fairify_data.mat deleted file mode 100644 index 21e036e4a9..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_fairify_data.mat and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_model_fc.mat b/code/nnv/examples/NN/Fair/adult_model_fc.mat deleted file mode 100644 index 5f6ef3cd10..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_model_fc.mat and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_my_models2/model_0.onnx b/code/nnv/examples/NN/Fair/adult_my_models2/model_0.onnx deleted file mode 100644 index b79fde624f..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_my_models2/model_0.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_my_models2/model_1.onnx b/code/nnv/examples/NN/Fair/adult_my_models2/model_1.onnx deleted file mode 100644 index c25b4b38fa..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_my_models2/model_1.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-1.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-1.onnx deleted file mode 100644 index d9b4aec052..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-1.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-10.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-10.onnx deleted file mode 100644 index c869824d54..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-10.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-11.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-11.onnx deleted file mode 100644 index 849a9c5f72..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-11.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-12.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-12.onnx deleted file mode 100644 index 84e09de72e..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-12.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-2.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-2.onnx deleted file mode 100644 index 3cc8038f88..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-2.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-3.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-3.onnx deleted file mode 100644 index a4c32db1b4..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-3.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-4.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-4.onnx deleted file mode 100644 index 2218517a7a..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-4.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-5.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-5.onnx deleted file mode 100644 index 05bf5e98ba..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-5.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-6.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-6.onnx deleted file mode 100644 index be57bb3a34..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-6.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-7.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-7.onnx deleted file mode 100644 index a6ed4838fb..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-7.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-8.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-8.onnx deleted file mode 100644 index 7c34f6efa3..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-8.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx/AC-9.onnx b/code/nnv/examples/NN/Fair/adult_onnx/AC-9.onnx deleted file mode 100644 index 8c48e35f09..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx/AC-9.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-1.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-1.onnx deleted file mode 100644 index da007ffc18..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-1.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-10.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-10.onnx deleted file mode 100644 index 89399f8d51..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-10.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-11.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-11.onnx deleted file mode 100644 index b9c0e53e32..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-11.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-12.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-12.onnx deleted file mode 100644 index e4687e9aa6..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-12.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-2.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-2.onnx deleted file mode 100644 index d5440cf338..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-2.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-3.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-3.onnx deleted file mode 100644 index 5ba9ed7b8c..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-3.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-4.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-4.onnx deleted file mode 100644 index 841aa5a26f..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-4.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-5.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-5.onnx deleted file mode 100644 index 568c72f702..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-5.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-6.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-6.onnx deleted file mode 100644 index a3c30e8853..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-6.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-7.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-7.onnx deleted file mode 100644 index 3e03722530..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-7.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-8.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-8.onnx deleted file mode 100644 index c1cfc80b84..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-8.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/adult_onnx2/AC-9.onnx b/code/nnv/examples/NN/Fair/adult_onnx2/AC-9.onnx deleted file mode 100644 index dd6d2f78b6..0000000000 Binary files a/code/nnv/examples/NN/Fair/adult_onnx2/AC-9.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/fair_model_10_50_10.onnx b/code/nnv/examples/NN/Fair/fair_model_10_50_10.onnx deleted file mode 100644 index c206e7e862..0000000000 Binary files a/code/nnv/examples/NN/Fair/fair_model_10_50_10.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/fair_model_50_100_50.onnx b/code/nnv/examples/NN/Fair/fair_model_50_100_50.onnx deleted file mode 100644 index 3df6e8c658..0000000000 Binary files a/code/nnv/examples/NN/Fair/fair_model_50_100_50.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/fair_model_ffnn_pytorch_50_100_50.onnx b/code/nnv/examples/NN/Fair/fair_model_ffnn_pytorch_50_100_50.onnx deleted file mode 100644 index 9d09bffc4d..0000000000 Binary files a/code/nnv/examples/NN/Fair/fair_model_ffnn_pytorch_50_100_50.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/results_verify_fdia_ffnn.mat b/code/nnv/examples/NN/Fair/results_verify_fdia_ffnn.mat deleted file mode 100644 index d6bf21615a..0000000000 Binary files a/code/nnv/examples/NN/Fair/results_verify_fdia_ffnn.mat and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/robustness_results_ex1.mat b/code/nnv/examples/NN/Fair/robustness_results_ex1.mat deleted file mode 100644 index 4031700fb4..0000000000 Binary files a/code/nnv/examples/NN/Fair/robustness_results_ex1.mat and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/test_data.mat b/code/nnv/examples/NN/Fair/test_data.mat deleted file mode 100644 index 5d2e65ff88..0000000000 Binary files a/code/nnv/examples/NN/Fair/test_data.mat and /dev/null differ diff --git a/code/nnv/examples/NN/Fair/training.m b/code/nnv/examples/NN/Fair/training.m deleted file mode 100644 index 249d01db6e..0000000000 --- a/code/nnv/examples/NN/Fair/training.m +++ /dev/null @@ -1,78 +0,0 @@ -%% Training of an ADULT classifier (NN) -% Code based on a few examples -% Data Preprocessing: https://github.com/jonathanlxy/MLproject-UCI-Adult-Income-Classification -% Ideas: https://github.com/LebronX/DeepGemini-public/blob/main/src/German/german_fairness_training.py -% Implementattion/Traihttps://github.com/LebronX/DeepGemini-public/blob/main/src/German/german_fairness_training.pyning - -t = tic; % track total time for training - -%% Read data -Train = csvread('finalset_cleaned_train.csv', 1, 0); -Test = csvread('finalset_cleaned_test.csv', 1, 0); - -% For the training dataset -XTrain = Train(:, 1:end-1); % All rows, but exclude the last column -YTrain = Train(:, end); % All rows, only the last column - -% For the testing dataset -XTest = Test(:, 1:end-1); % All rows, but exclude the last column -YTest = Test(:, end); % All rows, only the last column - -YTrain = categorical(YTrain); -YTest = categorical(YTest); - -N = 13; % Number of features after preprocessing -numClasses = 2; % For binary classification - -%% Neural Network -layers = [ - featureInputLayer(N) - - fullyConnectedLayer(50) - reluLayer; - - fullyConnectedLayer(100) - reluLayer; - - fullyConnectedLayer(50) - reluLayer; - - fullyConnectedLayer(numClasses) - softmaxLayer - classificationLayer]; - -% Training options -options = trainingOptions('adam', ... - 'InitialLearnRate', 0.01, ... - 'MaxEpochs', 20, ... - 'LearnRateSchedule', 'piecewise', ... - 'LearnRateDropFactor', 0.2, ... - 'LearnRateDropPeriod', 5, ... - 'MiniBatchSize', 64, ... - 'Shuffle', 'every-epoch', ... - 'ValidationData', {XTest, YTest}, ... - 'ValidationFrequency', 30, ... - 'Verbose', true, ... - 'Plots', 'training-progress'); - -% Train network -net = trainNetwork(XTrain,YTrain,layers,options); - -% Get Accuracy -YPred = predict(net, XTest); -YPred = round(YPred); - -% Convert YPred to categorical for comparison -YPredCategorical = categorical(YPred); - -accuracy = sum(YPredCategorical == YTest) / numel(YTest); -disp("Validation accuracy = "+string(accuracy)); - -% Save model -disp("Saving model..."); -save('adult_model_fc.mat', 'net', 'accuracy'); - -% Save test data for verification -save('test_data.mat', 'XTest', 'YTest'); - -toc(t); \ No newline at end of file diff --git a/code/nnv/examples/NN/Fair/verify.asv b/code/nnv/examples/NN/Fair/verify.asv deleted file mode 100644 index a9e98886b0..0000000000 --- a/code/nnv/examples/NN/Fair/verify.asv +++ /dev/null @@ -1,200 +0,0 @@ -%% Fairness Verification of Adult Classification Model (NN) - -% % Load network -% ac_model = load('adult_model_fc.mat'); -% -% % Create NNV model -% net = matlab2nnv(ac_model.net); - -% 50_100_50 model -onnx_model_1 = fullfile('fair_model_ffnn_pytorch_50_100_50.onnx'); - -% Load the ONNX file as DAGNetwork -netONNX = importONNXNetwork(onnx_model_1, 'OutputLayerType', 'classification', 'InputDataFormats', {'BC'}); - -analyzeNetwork(netONNX) - -% Convert the DAGNetwork to NNV format -net = matlab2nnv(netONNX); - -% Jimmy Rigged Fix: manually edit ouput size -net.OutputSize = 2; - -% Load data -load("adult_fair_data.mat", 'X', 'y'); -X_test_loaded = permute(X, [2, 1]); % change this for matlab expected format -y_test_loaded = y+1; % update labels - -% Normalize features in X_test_loaded -min_values = min(X_test_loaded, [], 2); -max_values = max(X_test_loaded, [], 2); - -% Ensure no division by zero for constant features -variableFeatures = max_values - min_values > 0; -min_values(~variableFeatures) = 0; % Avoids changing constant features -max_values(~variableFeatures) = 1; % Avoids division by zero - -% % Apply normalization -% X_test_loaded(:, variableFeatures) = (X_test_loaded(:, variableFeatures) - min_values(variableFeatures)) ./ (max_values(variableFeatures) - min_values(variableFeatures)); - -% Count total observations -total_obs = size(X_test_loaded, 2); -% disp(['There are total ', num2str(total_obs), ' observations']); - -% Number of observations we want to test -numObs = 100; - -%% Verification - -% to save results (robustness and time) -results = zeros(numObs,2); - -% First, we define the reachability options -reachOptions = struct; % initialize -reachOptions.reachMethod = 'relax-star-area'; % using approxiate method - -nR = 75; % ---> just chosen arbitrarily - -% ADJUST epsilon value here -epsilon = [0.0]; -% epsilon = [0.001,0.01,0.25]; - -% -% Set up results -% -nE = 1; %% will need to update later -res = zeros(numObs,nE); % robust result, changed from total_obs to 123 -time = zeros(numObs,nE); % computation time, changed from total_obs to 123 -met = repmat("relax", [numObs, nE]); % method used to compute result, changed from total_obs to 123 - -% Randomly select 20 observations -% rng(500); % Set a seed for reproducibility -rand_indices = randsample(total_obs, numObs); - -for e=1:length(epsilon) - % Reset the timeout flag - assignin('base', 'timeoutOccurred', false); - - % Create and configure the timer - verificationTimer = timer; - verificationTimer.StartDelay = 500; % Set timer for 200 seconds - verificationTimer.TimerFcn = @(myTimerObj, thisEvent) ... - assignin('base', 'timeoutOccurred', true); - start(verificationTimer); % Start the timer - - for i=1:numObs - idx = rand_indices(i); - [IS, xRand] = L_inf_attack(X_test_loaded(:, idx), epsilon(e), nR, min_values, max_values); - - t = tic; % Start timing the verification for each sample - - try - for xR=1:length(nR+3) - im = xRand(:, xR); - predictedLabels = net.evaluate(im); - [~, Pred] = max(predictedLabels); - if Pred == y_test_loaded(i) - res(i,e) = 0; % counterexample found - time(i,e) = toc(t); - met(i,e) = "counterexample"; - continue; - end - end - - temp = net.verify_robustness(IS, reachOptions, y_test_loaded(i)); - if temp ~= 1 && temp ~= 0 - reachOptions.reachMethod = 'approx-star'; - temp = net.verify_robustness(IS, reachOptions, y_test_loaded(i)); - met(i,e) = 'approx'; - end - res(i,e) = temp; % robust result - catch ME - met(i,e) = ME.message; - temp = -1; - end - - time(i,e) = toc(t); % store computation time - - % Check for timeout flag - if evalin('base', 'timeoutOccurred') - disp(['Timeout reached for epsilon = ', num2str(epsilon(e)), ': stopping verification for this epsilon.']); - res(i+1:end,e) = 2; % Mark remaining as unknown - break; % Exit the inner loop after timeout - end - - % Reset reachOptions - reachOptions.reachMethod = 'relax-star-area'; - reachOptions.relaxFactor = 0.5; - end - - % Summary results, stopping, and deleting the timer should be outside the inner loop - stop(verificationTimer); - delete(verificationTimer); - - % Get summary results - N = numObs; - rob = sum(res(:,e)==1); - not_rob = sum(res(:,e) == 0); - unk = sum(res(:,e) == 2); - totalTime = sum(time(:,e)); - avgTime = totalTime/N; - - % Print results to screen - disp("======= ROBUSTNESS RESULTS e: "+string(epsilon(e))+" ==========") - disp(" "); - disp("Number of robust samples = "+string(rob)+ ", equivalent to " + string(100*rob/N) + "% of the samples."); - disp("Number of not robust samples = " +string(not_rob)+ ", equivalent to " + string(100*not_rob/N) + "% of the samples.") - disp("Number of unknown samples = "+string(unk)+ ", equivalent to " + string(100*unk/N) + "% of the samples."); - disp(" "); - disp("It took a total of "+string(totalTime) + " seconds to compute the verification results, an average of "+string(avgTime)+" seconds per sample"); -end - - -%% Helper Function -% Adjusted for fairness check -> only apply perturbation to desired -% sensitive feature. -function [IS, xRand] = L_inf_attack(x, epsilon, nR, min_values, max_values) - % Apply a L-infinity attack of value epsilon on selected features of input image x - % where VariableFeatures is true. - % Return an ImageStar (IS) and random images from initial set - SampleSize = size(x); - - % Initialize disturbance to only affect specified sensitive rows - disturbance = zeros(SampleSize, "like", x); - specific_rows = [9]; % Rows with specific perturbations - specific_epsilons = [1]; % Corresponding specific perturbations - - % Apply specific perturbations to rows 8 and 9 - for i = 1:length(specific_rows) - if specific_rows(i) <= size(x, 1) - disturbance(specific_rows(i), :) = specific_epsilons(i); - else - error('The input data does not have enough rows.'); - end - end - - % Apply general epsilon to all other rows except 8 and 9 - for row = 1:size(x, 1) - if ~ismember(row, specific_rows) - disturbance(row, :) = epsilon; - end - end - - % Calculate disturbed lower and upper bounds considering min and max values - lb = max(x - disturbance, min_values); - ub = min(x + disturbance, max_values); - - IS = ImageStar(single(lb), single(ub)); % default: single (assume onnx input models) - - % Create random images from initial set - % Adjusted reshaping according to your specific needs - lb = reshape(lb, [13,1]); % Update the reshape parameters as per your actual data dimension - ub = reshape(ub, [13,1]); - xB = Box(single(lb), single(ub)); - xRand = xB.sample(nR); - xRand = reshape(xRand,[13,nR]); - xRand(:,nR+1) = x; % add original image - xRand(:,nR+2) = IS.im_lb; % add lower bound image - xRand(:,nR+3) = IS.im_ub; % add upper bound image -end - diff --git a/code/nnv/examples/NN/Fair/verify.m b/code/nnv/examples/NN/Fair/verify.m deleted file mode 100644 index a9e98886b0..0000000000 --- a/code/nnv/examples/NN/Fair/verify.m +++ /dev/null @@ -1,200 +0,0 @@ -%% Fairness Verification of Adult Classification Model (NN) - -% % Load network -% ac_model = load('adult_model_fc.mat'); -% -% % Create NNV model -% net = matlab2nnv(ac_model.net); - -% 50_100_50 model -onnx_model_1 = fullfile('fair_model_ffnn_pytorch_50_100_50.onnx'); - -% Load the ONNX file as DAGNetwork -netONNX = importONNXNetwork(onnx_model_1, 'OutputLayerType', 'classification', 'InputDataFormats', {'BC'}); - -analyzeNetwork(netONNX) - -% Convert the DAGNetwork to NNV format -net = matlab2nnv(netONNX); - -% Jimmy Rigged Fix: manually edit ouput size -net.OutputSize = 2; - -% Load data -load("adult_fair_data.mat", 'X', 'y'); -X_test_loaded = permute(X, [2, 1]); % change this for matlab expected format -y_test_loaded = y+1; % update labels - -% Normalize features in X_test_loaded -min_values = min(X_test_loaded, [], 2); -max_values = max(X_test_loaded, [], 2); - -% Ensure no division by zero for constant features -variableFeatures = max_values - min_values > 0; -min_values(~variableFeatures) = 0; % Avoids changing constant features -max_values(~variableFeatures) = 1; % Avoids division by zero - -% % Apply normalization -% X_test_loaded(:, variableFeatures) = (X_test_loaded(:, variableFeatures) - min_values(variableFeatures)) ./ (max_values(variableFeatures) - min_values(variableFeatures)); - -% Count total observations -total_obs = size(X_test_loaded, 2); -% disp(['There are total ', num2str(total_obs), ' observations']); - -% Number of observations we want to test -numObs = 100; - -%% Verification - -% to save results (robustness and time) -results = zeros(numObs,2); - -% First, we define the reachability options -reachOptions = struct; % initialize -reachOptions.reachMethod = 'relax-star-area'; % using approxiate method - -nR = 75; % ---> just chosen arbitrarily - -% ADJUST epsilon value here -epsilon = [0.0]; -% epsilon = [0.001,0.01,0.25]; - -% -% Set up results -% -nE = 1; %% will need to update later -res = zeros(numObs,nE); % robust result, changed from total_obs to 123 -time = zeros(numObs,nE); % computation time, changed from total_obs to 123 -met = repmat("relax", [numObs, nE]); % method used to compute result, changed from total_obs to 123 - -% Randomly select 20 observations -% rng(500); % Set a seed for reproducibility -rand_indices = randsample(total_obs, numObs); - -for e=1:length(epsilon) - % Reset the timeout flag - assignin('base', 'timeoutOccurred', false); - - % Create and configure the timer - verificationTimer = timer; - verificationTimer.StartDelay = 500; % Set timer for 200 seconds - verificationTimer.TimerFcn = @(myTimerObj, thisEvent) ... - assignin('base', 'timeoutOccurred', true); - start(verificationTimer); % Start the timer - - for i=1:numObs - idx = rand_indices(i); - [IS, xRand] = L_inf_attack(X_test_loaded(:, idx), epsilon(e), nR, min_values, max_values); - - t = tic; % Start timing the verification for each sample - - try - for xR=1:length(nR+3) - im = xRand(:, xR); - predictedLabels = net.evaluate(im); - [~, Pred] = max(predictedLabels); - if Pred == y_test_loaded(i) - res(i,e) = 0; % counterexample found - time(i,e) = toc(t); - met(i,e) = "counterexample"; - continue; - end - end - - temp = net.verify_robustness(IS, reachOptions, y_test_loaded(i)); - if temp ~= 1 && temp ~= 0 - reachOptions.reachMethod = 'approx-star'; - temp = net.verify_robustness(IS, reachOptions, y_test_loaded(i)); - met(i,e) = 'approx'; - end - res(i,e) = temp; % robust result - catch ME - met(i,e) = ME.message; - temp = -1; - end - - time(i,e) = toc(t); % store computation time - - % Check for timeout flag - if evalin('base', 'timeoutOccurred') - disp(['Timeout reached for epsilon = ', num2str(epsilon(e)), ': stopping verification for this epsilon.']); - res(i+1:end,e) = 2; % Mark remaining as unknown - break; % Exit the inner loop after timeout - end - - % Reset reachOptions - reachOptions.reachMethod = 'relax-star-area'; - reachOptions.relaxFactor = 0.5; - end - - % Summary results, stopping, and deleting the timer should be outside the inner loop - stop(verificationTimer); - delete(verificationTimer); - - % Get summary results - N = numObs; - rob = sum(res(:,e)==1); - not_rob = sum(res(:,e) == 0); - unk = sum(res(:,e) == 2); - totalTime = sum(time(:,e)); - avgTime = totalTime/N; - - % Print results to screen - disp("======= ROBUSTNESS RESULTS e: "+string(epsilon(e))+" ==========") - disp(" "); - disp("Number of robust samples = "+string(rob)+ ", equivalent to " + string(100*rob/N) + "% of the samples."); - disp("Number of not robust samples = " +string(not_rob)+ ", equivalent to " + string(100*not_rob/N) + "% of the samples.") - disp("Number of unknown samples = "+string(unk)+ ", equivalent to " + string(100*unk/N) + "% of the samples."); - disp(" "); - disp("It took a total of "+string(totalTime) + " seconds to compute the verification results, an average of "+string(avgTime)+" seconds per sample"); -end - - -%% Helper Function -% Adjusted for fairness check -> only apply perturbation to desired -% sensitive feature. -function [IS, xRand] = L_inf_attack(x, epsilon, nR, min_values, max_values) - % Apply a L-infinity attack of value epsilon on selected features of input image x - % where VariableFeatures is true. - % Return an ImageStar (IS) and random images from initial set - SampleSize = size(x); - - % Initialize disturbance to only affect specified sensitive rows - disturbance = zeros(SampleSize, "like", x); - specific_rows = [9]; % Rows with specific perturbations - specific_epsilons = [1]; % Corresponding specific perturbations - - % Apply specific perturbations to rows 8 and 9 - for i = 1:length(specific_rows) - if specific_rows(i) <= size(x, 1) - disturbance(specific_rows(i), :) = specific_epsilons(i); - else - error('The input data does not have enough rows.'); - end - end - - % Apply general epsilon to all other rows except 8 and 9 - for row = 1:size(x, 1) - if ~ismember(row, specific_rows) - disturbance(row, :) = epsilon; - end - end - - % Calculate disturbed lower and upper bounds considering min and max values - lb = max(x - disturbance, min_values); - ub = min(x + disturbance, max_values); - - IS = ImageStar(single(lb), single(ub)); % default: single (assume onnx input models) - - % Create random images from initial set - % Adjusted reshaping according to your specific needs - lb = reshape(lb, [13,1]); % Update the reshape parameters as per your actual data dimension - ub = reshape(ub, [13,1]); - xB = Box(single(lb), single(ub)); - xRand = xB.sample(nR); - xRand = reshape(xRand,[13,nR]); - xRand(:,nR+1) = x; % add original image - xRand(:,nR+2) = IS.im_lb; % add lower bound image - xRand(:,nR+3) = IS.im_ub; % add upper bound image -end - diff --git a/code/nnv/examples/NN/Fair/verify_fairify.m b/code/nnv/examples/NN/Fair/verify_fairify.m deleted file mode 100644 index 44e2a267aa..0000000000 --- a/code/nnv/examples/NN/Fair/verify_fairify.m +++ /dev/null @@ -1,295 +0,0 @@ -%% Fairness Verification of Adult Classification Model (NN) -% Comparison for the models used in Fairify - -% Suppress warnings -warning('off', 'nnet_cnn_onnx:onnx:WarnAPIDeprecation'); -warning('off', 'nnet_cnn_onnx:onnx:FillingInClassNames'); - -%% Load data into NNV -warning('on', 'verbose') - -%% Setup -clear; clc; -modelDir = './adult_onnx'; % Directory containing ONNX models -onnxFiles = dir(fullfile(modelDir, '*.onnx')); % List all .onnx files - -load("adult_fairify2_data.mat", 'X', 'y'); % Load data once - -% % Display the size of the input and output data -% disp('Size of X:'); -% disp(size(X)); % This should show [N, 13] -% -% disp('Size of y:'); -% disp(size(y)); % This should show [N, 1] or [N] - - -%% Loop through each model -for k = 1:length(2) - % onnx_model_path = fullfile(onnxFiles(k).folder, onnxFiles(k).name); - onnx_model_path = fullfile("adult_my_models2/model_0.onnx"); - % onnx_model_path = fullfile("adult_onnx/AC-1.onnx"); - - % Load the ONNX file as DAGNetwork - netONNX = importONNXNetwork(onnx_model_path, 'OutputLayerType', 'classification', 'InputDataFormats', {'BC'}); - - % analyzeNetwork(netONNX) - - % Convert the DAGNetwork to NNV format - net = matlab2nnv(netONNX); - - % Jimmy Rigged Fix: manually edit ouput size - net.OutputSize = 2; - - % disp(net) - - X_test_loaded = permute(X, [2, 1]); - y_test_loaded = y+1; % update labels - - % Normalize features in X_test_loaded - min_values = min(X_test_loaded, [], 2); - max_values = max(X_test_loaded, [], 2); - - % Ensure no division by zero for constant features - variableFeatures = max_values - min_values > 0; - min_values(~variableFeatures) = 0; % Avoids changing constant features - max_values(~variableFeatures) = 1; % Avoids division by zero - - % Normalizing X_test_loaded - X_test_loaded = (X_test_loaded - min_values) ./ (max_values - min_values); - - % % Print normalized values for a few samples - % disp('First few normalized inputs in MATLAB:'); - % disp(X_test_loaded(:, 1:5)); - % - % % Print model outputs for a few samples - % disp('First few model outputs in MATLAB:'); - % for i = 1:5 - % im = X_test_loaded(:, i); - % predictedLabels = net.evaluate(im); - % disp(predictedLabels); - % end - - % Count total observations - total_obs = size(X_test_loaded, 2); - % disp(['There are total ', num2str(total_obs), ' observations']); - - % % - % % Test accuracy --> verify matches with python - % % - % total_corr = 0; - % for i=1:total_obs - % im = X_test_loaded(:, i); - % predictedLabels = net.evaluate(im); - % [~, Pred] = min(predictedLabels); - % disp(Pred) - % TrueLabel = y_test_loaded(i); - % disp(TrueLabel) - % if Pred == TrueLabel - % total_corr = total_corr + 1; - % end - % end - % disp(['Test Accuracy: ', num2str(total_corr/total_obs)]); - - % Number of observations we want to test - numObs = 100; - - %% Verification - - % to save results (robustness and time) - results = zeros(numObs,2); - - % First, we define the reachability options - reachOptions = struct; % initialize - reachOptions.reachMethod = 'relax-star-area'; % using relax method - reachOptions.relaxFactor = 0.5; - - nR = 50; % ---> just chosen arbitrarily - - % ADJUST epsilon value here - % epsilon = [0.01]; - epsilon = [0.0,0.001,0.01]; - % epsilon = [0.00001]; - - % - % Set up results - % - nE = 3; %% will need to update later - res = zeros(numObs,nE); % robust result - time = zeros(numObs,nE); % computation time - met = repmat("relax", [numObs, nE]); % method used to compute result - - - % Randomly select observations - rng(500); % Set a seed for reproducibility - rand_indices = randsample(total_obs, numObs); - - for e=1:length(epsilon) - % Reset the timeout flag - assignin('base', 'timeoutOccurred', false); - - % Create and configure the timer - verificationTimer = timer; - verificationTimer.StartDelay = 600; % Set timer for 10 minutes - verificationTimer.TimerFcn = @(myTimerObj, thisEvent) ... - assignin('base', 'timeoutOccurred', true); - start(verificationTimer); % Start the timer - - ce_count = 0; - exact_count = 0; - ap_count = 0; - - for i=1:numObs - idx = rand_indices(i); - [IS, xRand] = perturbation(X_test_loaded(:, idx), epsilon(e), nR, min_values, max_values); - - skipTryCatch = false; % Initialize the flag - t = tic; % Start timing the verification for each sample - % - % Try falsification, then approx star, if unknown, try exact-star - % - % for xR=1:length(nR+3) - % im = xRand(:, xR); - % predictedLabels = net.evaluate(im); - % [~, Pred] = min(predictedLabels); - % if Pred ~= y_test_loaded(idx) - % % disp(string(i)+" Counterexample found. "+string(Pred)+" "+string(y_test_loaded(idx))) - % res(i,e) = 0; % counterexample found - % ce_count = ce_count + 1; - % time(i,e) = toc(t); - % met(i,e) = "counterexample"; - % skipTryCatch = true; % Set the flag to skip try-catch block - % continue; - % end - % end - % if ~skipTryCatch - % try - % temp = net.verify_robustness(IS, reachOptions, y_test_loaded(idx)); - % if temp == 1 || temp == 0 - % ap_count = ap_count + 1; - % end - % % disp(string(i)+" Approx: "+string(temp)) - % if temp ~= 1 && temp ~= 0 - % exact_count = exact_count + 1; - % % reachOptions.reachMethod = 'approx-star'; - % reachOptions.reachMethod = 'exact-star'; - % temp = net.verify_robustness(IS, reachOptions, y_test_loaded(idx)); - % % disp(string(i)+" Exact: "+string(temp)) - % % met(i,e) = 'approx'; - % met(i,e) = 'exact'; - % end - % res(i,e) = temp; % robust result - % catch ME - % met(i,e) = ME.message; - % temp = -1; - % end - reachOptions.reachMethod = 'exact-star'; - temp = net.verify_robustness(IS, reachOptions, y_test_loaded(idx)); - % disp(string(i)+" Exact: "+string(temp)) - % met(i,e) = 'approx'; - met(i,e) = 'exact'; - res(i,e) = temp; % robust result - % end - - time(i,e) = toc(t); % store computation time - - % Check for timeout flag - if evalin('base', 'timeoutOccurred') - disp(['Timeout reached for epsilon = ', num2str(epsilon(e)), ': stopping verification for this epsilon.']); - res(i+1:end,e) = 2; % Mark remaining as unknown - break; % Exit the inner loop after timeout - end - - % Reset reachOptions - reachOptions.reachMethod = 'relax-star-area'; - reachOptions.relaxFactor = 0.5; - end - - disp("Counterexamples Found: "+string(ce_count)) - disp("Approx Method Found: "+string(ap_count)) - disp("Exact Method Found: "+string(exact_count)) - - % Summary results, stopping, and deleting the timer should be outside the inner loop - stop(verificationTimer); - delete(verificationTimer); - - % Get summary results - N = numObs; - rob = sum(res(:,e)==1); - not_rob = sum(res(:,e) == 0); - unk = sum(res(:,e) == 2); - totalTime = sum(time(:,e)); - avgTime = totalTime/N; - - % Print results to screen - % fprintf('Model: %s\n', onnxFiles(k).name); - disp("======= ROBUSTNESS RESULTS e: "+string(epsilon(e))+" ==========") - disp(" "); - disp("Number of fair samples = "+string(rob)+ ", equivalent to " + string(100*rob/N) + "% of the samples."); - disp("Number of non-fair samples = " +string(not_rob)+ ", equivalent to " + string(100*not_rob/N) + "% of the samples.") - disp("Number of unknown samples = "+string(unk)+ ", equivalent to " + string(100*unk/N) + "% of the samples."); - disp(" "); - disp("It took a total of "+string(totalTime) + " seconds to compute the verification results, an average of "+string(avgTime)+" seconds per sample"); - end -end - - -%% Helper Function -% Adjusted for fairness check -> only apply perturbation to desired feature. -function [IS, xRand] = perturbation(x, epsilon, nR, min_values, max_values) - % Applies perturbations on selected features of input sample x - % Return an ImageStar (IS) and random images from initial set - SampleSize = size(x); - - disturbance = zeros(SampleSize, "like", x); - sensitive_rows = [9]; - nonsensitive_rows = [1,10,11,12]; - - % Flip the sensitive attribute - if x(sensitive_rows) == 1 - x(sensitive_rows) = 0; - else - x(sensitive_rows) = 1; - end - - % % Apply specific perturbations to sensitive features - % for i = 1:length(sensitive_rows) - % if sensitive_rows(i) <= size(x, 1) - % disturbance(sensitive_rows(i), :) = sensitive_epsilons(i); - % else - % error('The input data does not have enough rows.'); - % end - % end - - % Apply epsilon perturbation to non-sensitive numerical features - for i = 1:length(nonsensitive_rows) - if nonsensitive_rows(i) <= size(x, 1) - disturbance(nonsensitive_rows(i), :) = epsilon; - else - error('The input data does not have enough rows.'); - end - end - - % % Apply general epsilon to all other rows except 8 and 9 - % for row = 1:size(x, 1) - % if ~ismember(row, sensitive_rows) - % disturbance(row, :) = epsilon; - % end - % end - - % Calculate disturbed lower and upper bounds considering min and max values - lb = max(x - disturbance, min_values); - ub = min(x + disturbance, max_values); - IS = ImageStar(single(lb), single(ub)); % default: single (assume onnx input models) - - % Create random samples from initial set - % Adjusted reshaping according to your specific needs - lb = reshape(lb, [13,1]); % Update the reshape parameters as per your actual data dimension - ub = reshape(ub, [13,1]); - xB = Box(single(lb), single(ub)); - xRand = xB.sample(nR); - xRand = reshape(xRand,[13,nR]); - xRand(:,nR+1) = x; % add original image - xRand(:,nR+2) = IS.im_lb; % add lower bound image - xRand(:,nR+3) = IS.im_ub; % add upper bound image -end - diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-1.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-1.onnx deleted file mode 100644 index da007ffc18..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-1.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-10.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-10.onnx deleted file mode 100644 index 89399f8d51..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-10.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-11.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-11.onnx deleted file mode 100644 index b9c0e53e32..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-11.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-12.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-12.onnx deleted file mode 100644 index e4687e9aa6..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-12.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-2.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-2.onnx deleted file mode 100644 index d5440cf338..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-2.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-3.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-3.onnx deleted file mode 100644 index 5ba9ed7b8c..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-3.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-4.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-4.onnx deleted file mode 100644 index 841aa5a26f..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-4.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-5.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-5.onnx deleted file mode 100644 index 568c72f702..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-5.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-6.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-6.onnx deleted file mode 100644 index a3c30e8853..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-6.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-7.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-7.onnx deleted file mode 100644 index 3e03722530..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-7.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-8.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-8.onnx deleted file mode 100644 index c1cfc80b84..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-8.onnx and /dev/null differ diff --git a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-9.onnx b/code/nnv/examples/NN/FairNNV/adult_onnx/AC-9.onnx deleted file mode 100644 index dd6d2f78b6..0000000000 Binary files a/code/nnv/examples/NN/FairNNV/adult_onnx/AC-9.onnx and /dev/null differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-1.onnx b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-1.onnx new file mode 100644 index 0000000000..1ae5bd2f3c Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-1.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-10.onnx b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-10.onnx new file mode 100644 index 0000000000..6646107391 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-10.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-11.onnx b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-11.onnx new file mode 100644 index 0000000000..166758a369 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-11.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-12.onnx b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-12.onnx new file mode 100644 index 0000000000..010b3a8b68 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-12.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-3.onnx b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-3.onnx new file mode 100644 index 0000000000..19a88ce923 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-3.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-4.onnx b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-4.onnx new file mode 100644 index 0000000000..b437868cf7 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-4.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-5.onnx b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-5.onnx new file mode 100644 index 0000000000..b188fbcd95 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_debiased_onnx/AC-5.onnx differ diff --git a/code/nnv/examples/NN/FairNNV/adult_verifiy.m b/code/nnv/examples/Submission/ICAIF24/adult_debiased_verify.m similarity index 56% rename from code/nnv/examples/NN/FairNNV/adult_verifiy.m rename to code/nnv/examples/Submission/ICAIF24/adult_debiased_verify.m index 845fcfdf99..251eb4edd4 100644 --- a/code/nnv/examples/NN/FairNNV/adult_verifiy.m +++ b/code/nnv/examples/Submission/ICAIF24/adult_debiased_verify.m @@ -1,5 +1,4 @@ -%% Fairness Verification of Adult Classification Model (NN) -% Comparison for the models used in Fairify +%% Exact Fairness Verification of Debiased Adult Classification Model (NN) % Suppress warnings warning('off', 'nnet_cnn_onnx:onnx:WarnAPIDeprecation'); @@ -10,14 +9,23 @@ %% Setup clear; clc; -modelDir = './adult_onnx'; % Directory containing ONNX models +modelDir = './adult_debiased_onnx'; % Directory containing ONNX models onnxFiles = dir(fullfile(modelDir, '*.onnx')); % List all .onnx files -load("adult_data.mat", 'X', 'y'); % load Adult data +load("./data/adult_data.mat", 'X', 'y'); % Load data once + +% Initialize results storage +results = {}; +% List of models to process +modelList = {'AC-1', 'AC-4', 'AC-3'}; %% Loop through each model for k = 1:length(onnxFiles) - + [~, modelName, ~] = fileparts(onnxFiles(k).name); + if any(strcmp(modelName, modelList)) + + clear net netONNX outputSet IS R + onnx_model_path = fullfile(onnxFiles(k).folder, onnxFiles(k).name); % Load the ONNX file as DAGNetwork @@ -26,7 +34,6 @@ % Convert the DAGNetwork to NNV format net = matlab2nnv(netONNX); - % Jimmy Rigged Fix: manually edit ouput size net.OutputSize = 2; X_test_loaded = permute(X, [2, 1]); @@ -47,38 +54,50 @@ % Count total observations total_obs = size(X_test_loaded, 2); % disp(['There are total ', num2str(total_obs), ' observations']); - + % Number of observations we want to test - numObs = 1000; + numObs = 100; + + % Test accuracy + total_corr= 0; + for i=1:total_obs + im = X_test_loaded(:, i); + predictedLabels = net.evaluate(im); + [~, Pred] = min(predictedLabels); + % disp(Pred) + TrueLabel = y_test_loaded(i); + % disp(TrueLabel) + if Pred == TrueLabel + total_corr = total_corr + 1; + end + end + disp("Accuracy of Model: "+string(total_corr/total_obs)); + %% Verification - % To save results (robustness and time) - results = zeros(numObs,2); - % First, we define the reachability options reachOptions = struct; % initialize - reachOptions.reachMethod = 'relax-star-area'; % using relax method - reachOptions.relaxFactor = 0.5; + reachOptions.reachMethod = 'exact-star'; - nR = 50; % ---> just chosen arbitrarily + % ADJUST epsilons value here + epsilon = [0.0,0.02,0.03,0.05,0.07,0.1]; + % -1 -> no perturbation to model + % 0.0 -> counterfactual fairness (flips sensitive attribute) + % >0.0 -> individual fairness (flips SA w/ perturbation of numerical features) - % ADJUST epsilon values here - epsilon = [0.001,0.01]; - - % Set up results - nE = 3; + nE = 3; res = zeros(numObs,nE); % robust result time = zeros(numObs,nE); % computation time - met = repmat("relax", [numObs, nE]); % method used to compute result + met = repmat("exact", [numObs, nE]); % method used to compute result - % Randomly select observations rng(500); % Set a seed for reproducibility rand_indices = randsample(total_obs, numObs); for e=1:length(epsilon) + clear R outputSet IS temp t % Reset the timeout flag assignin('base', 'timeoutOccurred', false); @@ -88,47 +107,47 @@ verificationTimer.TimerFcn = @(myTimerObj, thisEvent) ... assignin('base', 'timeoutOccurred', true); start(verificationTimer); % Start the timer - - % Iterate through observations - for i=38 + + + + for i=1:numObs idx = rand_indices(i); - [IS, xRand] = perturbationIF(X_test_loaded(:, idx), epsilon(e), nR, min_values, max_values); - - skipTryCatch = false; % Initialize the flag + im = X_test_loaded(:, idx); + + IS = perturbationIF(X_test_loaded(:, idx), epsilon(e), min_values, max_values); + t = tic; % Start timing the verification for each sample - % - % Try falsification, then relax star, if unknown, try exact-star - % - % Falsification - for xR=1:length(nR+3) - im = xRand(:, xR); - predictedLabels = net.evaluate(im); - [~, Pred] = min(predictedLabels); - if Pred ~= y_test_loaded(idx) - res(i,e) = 0; % counterexample found - time(i,e) = toc(t); - met(i,e) = "counterexample"; - skipTryCatch = true; % Set the flag to skip try-catch block - disp('Counter example found'); - continue; + + outputSet = net.reach(IS,reachOptions); % Generate output set + target = y_test_loaded(idx); + + R = Star; + % Process set + if ~isa(outputSet, "Star") + nr = length(outputSet); + R(nr) = Star; + for s=1:nr + R(s) = outputSet(s).toStar; end + else + R = outputSet; end - if ~skipTryCatch - try - % Relax star - temp = net.verify_robustness(IS, reachOptions, y_test_loaded(idx)); - % Exact star - if temp ~= 1 && temp ~= 0 - reachOptions.reachMethod = 'exact-star'; - temp = net.verify_robustness(IS, reachOptions, y_test_loaded(idx)); - met(i,e) = 'exact'; - end - res(i,e) = temp; % robust result - catch ME - met(i,e) = ME.message; - temp = -1; + + % Process fairness specification + target = net.robustness_set(target, 'min'); + + % Verify fairness + temp = 1; + for s = 1:length(R) + if verify_specification(R(s), target) ~= 1 + temp = 0; + break end end + + met(i,e) = 'exact'; + + res(i,e) = temp; % robust result time(i,e) = toc(t); % store computation time @@ -138,12 +157,8 @@ res(i+1:end,e) = 2; % Mark remaining as unknown break; % Exit the inner loop after timeout end - - % Reset reachOptions - reachOptions.reachMethod = 'relax-star-area'; - reachOptions.relaxFactor = 0.5; end - + % Summary results, stopping, and deleting the timer should be outside the inner loop stop(verificationTimer); delete(verificationTimer); @@ -165,13 +180,30 @@ disp("Number of unknown samples = "+string(unk)+ ", equivalent to " + string(100*unk/N) + "% of the samples."); disp(" "); disp("It took a total of "+string(totalTime) + " seconds to compute the verification results, an average of "+string(avgTime)+" seconds per sample"); + % Collect results for CSV + results{end+1} = {onnxFiles(k).name, epsilon(e), 100 * rob / N, 100 * not_rob / N, 100 * unk / N, totalTime, avgTime}; + end end end +%% Save results to CSV +% Get the current timestamp using datetime +timestamp = datetime('now', 'Format', 'yyyyMMdd_HHmmss'); +% Convert the datetime to a string +timestampStr = char(timestamp); +% Create the filename with the timestamp +csv_filename = ['./results/adult_verify_debiased_results_', timestampStr, '.csv']; +fid = fopen(csv_filename, 'w'); +fprintf(fid, 'Model,Epsilon,FairPercent,NonFairPercent,UnknownPercent,TotalTime,AvgTime\n'); +for r = 1:length(results) + fprintf(fid, '%s,%f,%f,%f,%f,%f,%f\n', results{r}{1}, results{r}{2}, results{r}{3}, results{r}{4}, results{r}{5}, results{r}{6}, results{r}{7}); +end +fclose(fid); +disp(['Results saved to ', csv_filename]); %% Helper Function % Apply perturbation (individual fairness) to sample -function [IS, xRand] = perturbationIF(x, epsilon, nR, min_values, max_values) +function IS = perturbationIF(x, epsilon, min_values, max_values) % Applies perturbations on selected features of input sample x % Return an ImageStar (IS) and random images from initial set SampleSize = size(x); @@ -181,35 +213,28 @@ nonsensitive_rows = [1,10,11,12]; % Flip the sensitive attribute - if x(sensitive_rows) == 1 - x(sensitive_rows) = 0; - else - x(sensitive_rows) = 1; + if epsilon ~= -1 + if x(sensitive_rows) == 1 + x(sensitive_rows) = 0; + else + x(sensitive_rows) = 1; + end end % Apply epsilon perturbation to non-sensitive numerical features for i = 1:length(nonsensitive_rows) - if nonsensitive_rows(i) <= size(x, 1) - disturbance(nonsensitive_rows(i), :) = epsilon; - else - error('The input data does not have enough rows.'); + if epsilon ~= -1 + if nonsensitive_rows(i) <= size(x, 1) + disturbance(nonsensitive_rows(i), :) = epsilon; + else + error('The input data does not have enough rows.'); + end end end % Calculate disturbed lower and upper bounds considering min and max values lb = max(x - disturbance, min_values); ub = min(x + disturbance, max_values); - IS = Star(single(lb), single(ub)); % default: single (assume onnx input models) - - % Create random samples from initial set - % Adjusted reshaping according to specific needs - lb = reshape(lb, [13,1]); - ub = reshape(ub, [13,1]); - xB = Box(single(lb), single(ub)); - xRand = xB.sample(nR); - xRand = reshape(xRand,[13,nR]); - xRand(:,nR+1) = x; % add original image - xRand(:,nR+2) = xB.lb; % add lower bound image - xRand(:,nR+3) = xB.ub; % add upper bound image + IS = ImageStar(single(lb), single(ub)); % default: single (assume onnx input models) end diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-1.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-1.onnx new file mode 100644 index 0000000000..ec00892ccf Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-1.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-10.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-10.onnx new file mode 100644 index 0000000000..6f70569a6d Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-10.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-11.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-11.onnx new file mode 100644 index 0000000000..60f6e9356f Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-11.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-12.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-12.onnx new file mode 100644 index 0000000000..17051914a3 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-12.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-2.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-2.onnx new file mode 100644 index 0000000000..bc87c35220 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-2.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-3.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-3.onnx new file mode 100644 index 0000000000..97a34e8371 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-3.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-4.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-4.onnx new file mode 100644 index 0000000000..33825bc84f Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-4.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-5.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-5.onnx new file mode 100644 index 0000000000..bfdd2e529f Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-5.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-6.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-6.onnx new file mode 100644 index 0000000000..b43370e94f Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-6.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-7.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-7.onnx new file mode 100644 index 0000000000..d46f160956 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-7.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-8.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-8.onnx new file mode 100644 index 0000000000..9b1fe6958e Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-8.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-9.onnx b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-9.onnx new file mode 100644 index 0000000000..f180c823c7 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/adult_onnx/AC-9.onnx differ diff --git a/code/nnv/examples/NN/FairNNV/adult_exact_verify.m b/code/nnv/examples/Submission/ICAIF24/adult_verify.m similarity index 61% rename from code/nnv/examples/NN/FairNNV/adult_exact_verify.m rename to code/nnv/examples/Submission/ICAIF24/adult_verify.m index 15590f10c2..7284e73287 100644 --- a/code/nnv/examples/NN/FairNNV/adult_exact_verify.m +++ b/code/nnv/examples/Submission/ICAIF24/adult_verify.m @@ -1,6 +1,4 @@ %% Exact Fairness Verification of Adult Classification Model (NN) -% Comparison for the models used in Fairify - % Suppress warnings warning('off', 'nnet_cnn_onnx:onnx:WarnAPIDeprecation'); warning('off', 'nnet_cnn_onnx:onnx:FillingInClassNames'); @@ -12,12 +10,22 @@ clear; clc; modelDir = './adult_onnx'; % Directory containing ONNX models onnxFiles = dir(fullfile(modelDir, '*.onnx')); % List all .onnx files -onnxFiles = onnxFiles(1); % simplify for debugging -load("adult_data.mat", 'X', 'y'); % Load data once +load("./data/adult_data.mat", 'X', 'y'); % Load data once + +% Initialize results storage +results = {}; + +% List of models to process +modelList = {'AC-1', 'AC-4', 'AC-3'}; %% Loop through each model for k = 1:length(onnxFiles) + [~, modelName, ~] = fileparts(onnxFiles(k).name); + if any(strcmp(modelName, modelList)) + + clear net netONNX outputSet IS R + onnx_model_path = fullfile(onnxFiles(k).folder, onnxFiles(k).name); % Load the ONNX file as DAGNetwork @@ -26,7 +34,6 @@ % Convert the DAGNetwork to NNV format net = matlab2nnv(netONNX); - % Jimmy Rigged Fix: manually edit ouput size net.OutputSize = 2; X_test_loaded = permute(X, [2, 1]); @@ -46,25 +53,36 @@ % Count total observations total_obs = size(X_test_loaded, 2); - % disp(['There are total ', num2str(total_obs), ' observations']); % Number of observations we want to test - numObs = 1000; + numObs = 100; + + % Test accuracy --> verify matches with python + total_corr= 0; + for i=1:total_obs + im = X_test_loaded(:, i); + predictedLabels = net.evaluate(im); + [~, Pred] = min(predictedLabels); + % disp(Pred) + TrueLabel = y_test_loaded(i); + % disp(TrueLabel) + if Pred == TrueLabel + total_corr = total_corr + 1; + end + end + disp("Accuracy of Model: "+string(total_corr/total_obs)); %% Verification - % To save results (robustness and time) - results = zeros(numObs,2); - % First, we define the reachability options reachOptions = struct; % initialize reachOptions.reachMethod = 'exact-star'; - nR = 50; % ---> just chosen arbitrarily - % ADJUST epsilons value here - % epsilon = [0.001,0.01]; - epsilon = 0.01; + epsilon = [0.0,0.02,0.03,0.05,0.07,0.1]; + % -1 -> no perturbation to model + % 0.0 -> counterfactual fairness (flips sensitive attribute) + % >0.0 -> individual fairness (flips SA w/ perturbation of numerical features) % Set up results nE = 3; @@ -77,6 +95,7 @@ rand_indices = randsample(total_obs, numObs); for e=1:length(epsilon) + clear R outputSet IS temp t % Reset the timeout flag assignin('base', 'timeoutOccurred', false); @@ -88,23 +107,47 @@ start(verificationTimer); % Start the timer - % for i=1:numObs - for i=57 + for i=1:numObs idx = rand_indices(i); IS = perturbationIF(X_test_loaded(:, idx), epsilon(e), min_values, max_values); - unsafeRegion = net.robustness_set(y_test_loaded(idx), 'min'); - t = tic; % Start timing the verification for each sample + outputSet = net.reach(IS,reachOptions); % Generate output set + target = y_test_loaded(idx); - temp = net.verify_robustness(IS, reachOptions, unsafeRegion); + R = Star; + % Process set + if ~isa(outputSet, "Star") + nr = length(outputSet); + R(nr) = Star; + for s=1:nr + R(s) = outputSet(s).toStar; + end + else + R = outputSet; + end + + % Process fairness specification + target = net.robustness_set(target, 'min'); + + % Verify fairness + temp = 1; + for s = 1:length(R) + if verify_specification(R(s), target) ~= 1 + temp = 0; + break + end + end + met(i,e) = 'exact'; - res(i,e) = temp; % robust result + + res(i,e) = temp; % robust result + time(i,e) = toc(t); % store computation time - if ~(temp == 1) - counterExs = getCounterRegion(IS,unsafeRegion,net.reachSet{end}); - end + % if ~(temp == 1) + % counterExs = getCounterRegion(IS,unsafeRegion,net.reachSet{end}); + % end % Check for timeout flag if evalin('base', 'timeoutOccurred') @@ -135,9 +178,26 @@ disp("Number of unknown samples = "+string(unk)+ ", equivalent to " + string(100*unk/N) + "% of the samples."); disp(" "); disp("It took a total of "+string(totalTime) + " seconds to compute the verification results, an average of "+string(avgTime)+" seconds per sample"); + % Collect results for CSV + results{end+1} = {onnxFiles(k).name, epsilon(e), 100 * rob / N, 100 * not_rob / N, 100 * unk / N, totalTime, avgTime}; + end end end +%% Save results to CSV +% Get the current timestamp using datetime +timestamp = datetime('now', 'Format', 'yyyyMMdd_HHmmss'); +% Convert the datetime to a string +timestampStr = char(timestamp); +% Create the filename with the timestamp +csv_filename = ['./results/adult_verify_results_', timestampStr, '.csv']; +fid = fopen(csv_filename, 'w'); +fprintf(fid, 'Model,Epsilon,FairPercent,NonFairPercent,UnknownPercent,TotalTime,AvgTime\n'); +for r = 1:length(results) + fprintf(fid, '%s,%f,%f,%f,%f,%f,%f\n', results{r}{1}, results{r}{2}, results{r}{3}, results{r}{4}, results{r}{5}, results{r}{6}, results{r}{7}); +end +fclose(fid); +disp(['Results saved to ', csv_filename]); %% Helper Function % Apply perturbation (individual fairness) to sample @@ -151,20 +211,24 @@ nonsensitive_rows = [1,10,11,12]; % Flip the sensitive attribute - if x(sensitive_rows) == 1 - x(sensitive_rows) = 0; - else - x(sensitive_rows) = 1; + if epsilon ~= -1 + if x(sensitive_rows) == 1 + x(sensitive_rows) = 0; + else + x(sensitive_rows) = 1; + end end - + % Apply epsilon perturbation to non-sensitive numerical features for i = 1:length(nonsensitive_rows) - if nonsensitive_rows(i) <= size(x, 1) - disturbance(nonsensitive_rows(i), :) = epsilon; - else - error('The input data does not have enough rows.'); + if epsilon ~= -1 + if nonsensitive_rows(i) <= size(x, 1) + disturbance(nonsensitive_rows(i), :) = epsilon; + else + error('The input data does not have enough rows.'); + end end - end + end % Calculate disturbed lower and upper bounds considering min and max values lb = max(x - disturbance, min_values); @@ -172,4 +236,3 @@ IS = Star(single(lb), single(ub)); % default: single (assume onnx input models) end - diff --git a/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-1.onnx b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-1.onnx new file mode 100644 index 0000000000..5b1d40fa8b Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-1.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-2.onnx b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-2.onnx new file mode 100644 index 0000000000..8c1fcf68c9 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-2.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-3.onnx b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-3.onnx new file mode 100644 index 0000000000..37396aed2d Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-3.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-4.onnx b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-4.onnx new file mode 100644 index 0000000000..499d6e966f Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-4.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-5.onnx b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-5.onnx new file mode 100644 index 0000000000..cd7c446a26 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-5.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-6.onnx b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-6.onnx new file mode 100644 index 0000000000..c6a0edfd70 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-6.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-7.onnx b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-7.onnx new file mode 100644 index 0000000000..21ff36a1f3 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-7.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-8.onnx b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-8.onnx new file mode 100644 index 0000000000..7ed2f9b705 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/bank_onnx/BM-8.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/bank_verify.m b/code/nnv/examples/Submission/ICAIF24/bank_verify.m new file mode 100644 index 0000000000..66efbcbb20 --- /dev/null +++ b/code/nnv/examples/Submission/ICAIF24/bank_verify.m @@ -0,0 +1,236 @@ +%% Exact Fairness Verification of Bank Marketing Classification Model (NN) + +% Suppress warnings +warning('off', 'nnet_cnn_onnx:onnx:WarnAPIDeprecation'); +warning('off', 'nnet_cnn_onnx:onnx:FillingInClassNames'); + +%% Load data into NNV +warning('on', 'verbose') + +%% Setup +clear; clc; +modelDir = './bank_onnx'; % Directory containing ONNX models +onnxFiles = dir(fullfile(modelDir, '*.onnx')); % List all .onnx files + +load("./data/bank_data.mat", 'X', 'y'); % Load data once + +% Initialize results storage +results = {}; + +modelList = {'BM-5','BM-6','BM-7'}; + + +%% Loop through each model +for k = 1:length(onnxFiles) + [~, modelName, ~] = fileparts(onnxFiles(k).name); + if any(strcmp(modelName, modelList)) + + clear net netONNX outputSet IS R + + onnx_model_path = fullfile(onnxFiles(k).folder, onnxFiles(k).name); + + % Load the ONNX file as DAGNetwork + netONNX = importONNXNetwork(onnx_model_path, 'OutputLayerType', 'classification', 'InputDataFormats', {'BC'}); + + % Convert the DAGNetwork to NNV format + net = matlab2nnv(netONNX); + + net.OutputSize = 2; + + X_test_loaded = permute(X, [2, 1]); + y_test_loaded = y+1; % update labels + + % Normalize features in X_test_loaded + min_values = min(X_test_loaded, [], 2); + max_values = max(X_test_loaded, [], 2); + + % Ensure no division by zero for constant features + variableFeatures = max_values - min_values > 0; + min_values(~variableFeatures) = 0; % Avoids changing constant features + max_values(~variableFeatures) = 1; % Avoids division by zero + + % Normalizing X_test_loaded + X_test_loaded = (X_test_loaded - min_values) ./ (max_values - min_values); + + % Count total observations + total_obs = size(X_test_loaded, 2); + + % Number of observations we want to test + numObs = 100; + + % Test accuracy --> verify matches with python + total_corr= 0; + for i=1:total_obs + im = X_test_loaded(:, i); + predictedLabels = net.evaluate(im); + [~, Pred] = min(predictedLabels); + % disp(Pred) + TrueLabel = y_test_loaded(i); + % disp(TrueLabel) + if Pred == TrueLabel + total_corr = total_corr + 1; + end + end + disp("Accuracy of Model: "+string(total_corr/total_obs)); + + + %% Verification + + % First, we define the reachability options + reachOptions = struct; % initialize + reachOptions.reachMethod = 'exact-star'; + + % ADJUST epsilons value here + epsilon = [0.0,0.02,0.03,0.05,0.07,0.1]; + % -1 -> no perturbation to model + % 0.0 -> counterfactual fairness (flips sensitive attribute) + % >0.0 -> individual fairness (flips SA w/ perturbation of numerical features) + + % Set up results + nE = 3; + res = zeros(numObs,nE); % robust result + time = zeros(numObs,nE); % computation time + met = repmat("exact", [numObs, nE]); % method used to compute result + + % Randomly select observations + rng(500); % Set a seed for reproducibility + rand_indices = randsample(total_obs, numObs); + + for e=1:length(epsilon) + clear R outputSet IS temp t + % Reset the timeout flag + assignin('base', 'timeoutOccurred', false); + + % Create and configure the timer + verificationTimer = timer; + verificationTimer.StartDelay = 600; % Set timer for 10 minutes + verificationTimer.TimerFcn = @(myTimerObj, thisEvent) ... + assignin('base', 'timeoutOccurred', true); + start(verificationTimer); % Start the timer + + + for i=1:numObs + idx = rand_indices(i); + IS = perturbationIF(X_test_loaded(:, idx), epsilon(e), min_values, max_values); + + t = tic; % Start timing the verification for each sample + outputSet = net.reach(IS,reachOptions); % Generate output set + target = y_test_loaded(idx); + + R = Star; + % Process set + if ~isa(outputSet, "Star") + nr = length(outputSet); + R(nr) = Star; + for s=1:nr + R(s) = outputSet(s).toStar; + end + else + R = outputSet; + end + + % Process fairness specification + target = net.robustness_set(target, 'min'); + + % Verify fairness + temp = 1; + for s = 1:length(R) + if verify_specification(R(s), target) ~= 1 + temp = 0; + break + end + end + + met(i,e) = 'exact'; + + res(i,e) = temp; % robust result + + time(i,e) = toc(t); % store computation time + + % Check for timeout flag + if evalin('base', 'timeoutOccurred') + disp(['Timeout reached for epsilon = ', num2str(epsilon(e)), ': stopping verification for this epsilon.']); + res(i+1:end,e) = 2; % Mark remaining as unknown + break; % Exit the inner loop after timeout + end + end + + % Summary results, stopping, and deleting the timer should be outside the inner loop + stop(verificationTimer); + delete(verificationTimer); + + % Get summary results + N = numObs; + rob = sum(res(:,e)==1); + not_rob = sum(res(:,e) == 0); + unk = sum(res(:,e) == 2); + totalTime = sum(time(:,e)); + avgTime = totalTime/N; + + % Print results to screen + fprintf('Model: %s\n', onnxFiles(k).name); + disp("======= FAIRNESS RESULTS e: "+string(epsilon(e))+" ==========") + disp(" "); + disp("Number of fair samples = "+string(rob)+ ", equivalent to " + string(100*rob/N) + "% of the samples."); + disp("Number of non-fair samples = " +string(not_rob)+ ", equivalent to " + string(100*not_rob/N) + "% of the samples.") + disp("Number of unknown samples = "+string(unk)+ ", equivalent to " + string(100*unk/N) + "% of the samples."); + disp(" "); + disp("It took a total of "+string(totalTime) + " seconds to compute the verification results, an average of "+string(avgTime)+" seconds per sample"); + % Collect results for CSV + results{end+1} = {onnxFiles(k).name, epsilon(e), 100 * rob / N, 100 * not_rob / N, 100 * unk / N, totalTime, avgTime}; + end + end +end + +%% Save results to CSV +% Get the current timestamp using datetime +timestamp = datetime('now', 'Format', 'yyyyMMdd_HHmmss'); +% Convert the datetime to a string +timestampStr = char(timestamp); +% Create the filename with the timestamp +csv_filename = ['./results/bank_verify_results_', timestampStr, '.csv']; +fid = fopen(csv_filename, 'w'); +fprintf(fid, 'Model,Epsilon,FairPercent,NonFairPercent,UnknownPercent,TotalTime,AvgTime\n'); +for r = 1:length(results) + fprintf(fid, '%s,%f,%f,%f,%f,%f,%f\n', results{r}{1}, results{r}{2}, results{r}{3}, results{r}{4}, results{r}{5}, results{r}{6}, results{r}{7}); +end +fclose(fid); +disp(['Results saved to ', csv_filename]); + + +%% Helper Function +% Apply perturbation (individual fairness) to sample +function IS = perturbationIF(x, epsilon, min_values, max_values) + % Applies perturbations on selected features of input sample x + % Return an ImageStar (IS) and random images from initial set + SampleSize = size(x); + + disturbance = zeros(SampleSize, "like", x); + sensitive_rows = [1]; + nonsensitive_rows = [6,12,13,14,15]; + + % Flip the sensitive attribute + if epsilon ~= -1 + if x(sensitive_rows) == 1 + x(sensitive_rows) = 0; + else + x(sensitive_rows) = 1; + end + end + + % Apply epsilon perturbation to non-sensitive numerical features + for i = 1:length(nonsensitive_rows) + if epsilon ~= -1 + if nonsensitive_rows(i) <= size(x, 1) + disturbance(nonsensitive_rows(i), :) = epsilon; + else + error('The input data does not have enough rows.'); + end + end + end + + % Calculate disturbed lower and upper bounds considering min and max values + lb = max(x - disturbance, min_values); + ub = min(x + disturbance, max_values); + IS = ImageStar(single(lb), single(ub)); % default: single (assume onnx input models) +end diff --git a/code/nnv/examples/NN/FairNNV/adult_data.mat b/code/nnv/examples/Submission/ICAIF24/data/adult_data.mat similarity index 86% rename from code/nnv/examples/NN/FairNNV/adult_data.mat rename to code/nnv/examples/Submission/ICAIF24/data/adult_data.mat index 99dc74fb1d..630532243e 100644 Binary files a/code/nnv/examples/NN/FairNNV/adult_data.mat and b/code/nnv/examples/Submission/ICAIF24/data/adult_data.mat differ diff --git a/code/nnv/examples/Submission/ICAIF24/data/bank_data.mat b/code/nnv/examples/Submission/ICAIF24/data/bank_data.mat new file mode 100644 index 0000000000..e3dcb94be0 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/data/bank_data.mat differ diff --git a/code/nnv/examples/Submission/ICAIF24/data/german_data.mat b/code/nnv/examples/Submission/ICAIF24/data/german_data.mat new file mode 100644 index 0000000000..a4702b71f7 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/data/german_data.mat differ diff --git a/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-1.onnx b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-1.onnx new file mode 100644 index 0000000000..f5b430ca38 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-1.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-2.onnx b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-2.onnx new file mode 100644 index 0000000000..f0af056113 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-2.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-3.onnx b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-3.onnx new file mode 100644 index 0000000000..40f280eb5f Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-3.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-4.onnx b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-4.onnx new file mode 100644 index 0000000000..69594ec707 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-4.onnx differ diff --git a/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-5.onnx b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-5.onnx new file mode 100644 index 0000000000..32fd110560 Binary files /dev/null and b/code/nnv/examples/Submission/ICAIF24/german_onnx/GC-5.onnx differ diff --git a/code/nnv/examples/NN/Fair/adult_exact_verify.m b/code/nnv/examples/Submission/ICAIF24/german_verify.m similarity index 55% rename from code/nnv/examples/NN/Fair/adult_exact_verify.m rename to code/nnv/examples/Submission/ICAIF24/german_verify.m index ab40eeb768..22d798f34d 100644 --- a/code/nnv/examples/NN/Fair/adult_exact_verify.m +++ b/code/nnv/examples/Submission/ICAIF24/german_verify.m @@ -1,5 +1,4 @@ -%% Fairness Verification of Adult Classification Model (NN) -% Comparison for the models used in Fairify +%% Exact Fairness Verification of German Credit Classification Model (NN) % Suppress warnings warning('off', 'nnet_cnn_onnx:onnx:WarnAPIDeprecation'); @@ -10,30 +9,33 @@ %% Setup clear; clc; -modelDir = './adult_onnx'; % Directory containing ONNX models +modelDir = './german_onnx'; % Directory containing ONNX models onnxFiles = dir(fullfile(modelDir, '*.onnx')); % List all .onnx files -load("adult_fairify2_data.mat", 'X', 'y'); % Load data once +load("./data/german_data.mat", 'X', 'y'); % Load data once + +% Initialize results storage +results = {}; + +modelList = {'GC-1','GC-2','GC-3'}; %% Loop through each model -for k = 1:length(2) - % onnx_model_path = fullfile(onnxFiles(k).folder, onnxFiles(k).name); - onnx_model_path = fullfile("adult_my_models2/model_0.onnx"); - % onnx_model_path = fullfile("adult_onnx/AC-1.onnx"); +for k = 1:length(onnxFiles) + [~, modelName, ~] = fileparts(onnxFiles(k).name); + if any(strcmp(modelName, modelList)) + + clear net netONNX outputSet IS R + + onnx_model_path = fullfile(onnxFiles(k).folder, onnxFiles(k).name); % Load the ONNX file as DAGNetwork netONNX = importONNXNetwork(onnx_model_path, 'OutputLayerType', 'classification', 'InputDataFormats', {'BC'}); - % analyzeNetwork(netONNX) - % Convert the DAGNetwork to NNV format net = matlab2nnv(netONNX); - % Jimmy Rigged Fix: manually edit ouput size net.OutputSize = 2; - - % disp(net) X_test_loaded = permute(X, [2, 1]); y_test_loaded = y+1; % update labels @@ -50,73 +52,52 @@ % Normalizing X_test_loaded X_test_loaded = (X_test_loaded - min_values) ./ (max_values - min_values); - % % Print normalized values for a few samples - % disp('First few normalized inputs in MATLAB:'); - % disp(X_test_loaded(:, 1:5)); - % - % % Print model outputs for a few samples - % disp('First few model outputs in MATLAB:'); - % for i = 1:5 - % im = X_test_loaded(:, i); - % predictedLabels = net.evaluate(im); - % disp(predictedLabels); - % end - % Count total observations total_obs = size(X_test_loaded, 2); - % disp(['There are total ', num2str(total_obs), ' observations']); - - % % - % % Test accuracy --> verify matches with python - % % - % total_corr = 0; - % for i=1:total_obs - % im = X_test_loaded(:, i); - % predictedLabels = net.evaluate(im); - % [~, Pred] = min(predictedLabels); - % disp(Pred) - % TrueLabel = y_test_loaded(i); - % disp(TrueLabel) - % if Pred == TrueLabel - % total_corr = total_corr + 1; - % end - % end - % disp(['Test Accuracy: ', num2str(total_corr/total_obs)]); % Number of observations we want to test numObs = 100; + + % Test accuracy + total_corr= 0; + for i=1:total_obs + im = X_test_loaded(:, i); + predictedLabels = net.evaluate(im); + [~, Pred] = min(predictedLabels); + % disp(Pred) + TrueLabel = y_test_loaded(i); + % disp(TrueLabel) + if Pred == TrueLabel + total_corr = total_corr + 1; + end + end + disp("Accuracy of Model: "+string(total_corr/total_obs)); + %% Verification - % to save results (robustness and time) - results = zeros(numObs,2); - % First, we define the reachability options reachOptions = struct; % initialize reachOptions.reachMethod = 'exact-star'; - reachOptions.relaxFactor = 0.5; - nR = 50; % ---> just chosen arbitrarily + % ADJUST epsilons value here + epsilon = [0.0,0.02,0.03,0.05,0.07,0.1]; + % -1 -> no perturbation to model + % 0.0 -> counterfactual fairness (flips sensitive attribute) + % >0.0 -> individual fairness (flips SA w/ perturbation of numerical features) - % ADJUST epsilon value here - % epsilon = [0.01]; - epsilon = [0.0,0.001,0.01]; - % epsilon = [0.00001]; - - % % Set up results - % - nE = 3; %% will need to update later + nE = 3; res = zeros(numObs,nE); % robust result time = zeros(numObs,nE); % computation time met = repmat("exact", [numObs, nE]); % method used to compute result - % Randomly select observations rng(500); % Set a seed for reproducibility rand_indices = randsample(total_obs, numObs); for e=1:length(epsilon) + clear R outputSet IS temp t % Reset the timeout flag assignin('base', 'timeoutOccurred', false); @@ -127,22 +108,42 @@ assignin('base', 'timeoutOccurred', true); start(verificationTimer); % Start the timer - ce_count = 0; - exact_count = 0; - ap_count = 0; for i=1:numObs idx = rand_indices(i); - IS = perturbation(X_test_loaded(:, idx), epsilon(e), min_values, max_values); - - + IS = perturbationIF(X_test_loaded(:, idx), epsilon(e), min_values, max_values); + t = tic; % Start timing the verification for each sample + outputSet = net.reach(IS,reachOptions); % Generate output set + target = y_test_loaded(idx); - temp = net.verify_robustness(IS, reachOptions, y_test_loaded(idx)); - % disp(string(i)+" Exact: "+string(temp)) + R = Star; + % Process set + if ~isa(outputSet, "Star") + nr = length(outputSet); + R(nr) = Star; + for s=1:nr + R(s) = outputSet(s).toStar; + end + else + R = outputSet; + end + + % Process fairness specification + target = net.robustness_set(target, 'min'); + + % Verify fairness + temp = 1; + for s = 1:length(R) + if verify_specification(R(s), target) ~= 1 + temp = 0; + break + end + end + met(i,e) = 'exact'; + res(i,e) = temp; % robust result - % end time(i,e) = toc(t); % store computation time @@ -167,42 +168,64 @@ avgTime = totalTime/N; % Print results to screen - % fprintf('Model: %s\n', onnxFiles(k).name); - disp("======= ROBUSTNESS RESULTS e: "+string(epsilon(e))+" ==========") + fprintf('Model: %s\n', onnxFiles(k).name); + disp("======= FAIRNESS RESULTS e: "+string(epsilon(e))+" ==========") disp(" "); disp("Number of fair samples = "+string(rob)+ ", equivalent to " + string(100*rob/N) + "% of the samples."); disp("Number of non-fair samples = " +string(not_rob)+ ", equivalent to " + string(100*not_rob/N) + "% of the samples.") disp("Number of unknown samples = "+string(unk)+ ", equivalent to " + string(100*unk/N) + "% of the samples."); disp(" "); disp("It took a total of "+string(totalTime) + " seconds to compute the verification results, an average of "+string(avgTime)+" seconds per sample"); + % Collect results for CSV + results{end+1} = {onnxFiles(k).name, epsilon(e), 100 * rob / N, 100 * not_rob / N, 100 * unk / N, totalTime, avgTime}; + end end end +%% Save results to CSV +% Get the current timestamp using datetime +timestamp = datetime('now', 'Format', 'yyyyMMdd_HHmmss'); +% Convert the datetime to a string +timestampStr = char(timestamp); +% Create the filename with the timestamp +csv_filename = ['./results/german_verify_results_', timestampStr, '.csv']; +fid = fopen(csv_filename, 'w'); +fprintf(fid, 'Model,Epsilon,FairPercent,NonFairPercent,UnknownPercent,TotalTime,AvgTime\n'); +for r = 1:length(results) + fprintf(fid, '%s,%f,%f,%f,%f,%f,%f\n', results{r}{1}, results{r}{2}, results{r}{3}, results{r}{4}, results{r}{5}, results{r}{6}, results{r}{7}); +end +fclose(fid); +disp(['Results saved to ', csv_filename]); + %% Helper Function -% Adjusted for fairness check -> only apply perturbation to desired feature. -function IS = perturbation(x, epsilon, min_values, max_values) +% Apply perturbation (individual fairness) to sample +function IS = perturbationIF(x, epsilon, min_values, max_values) % Applies perturbations on selected features of input sample x % Return an ImageStar (IS) and random images from initial set SampleSize = size(x); disturbance = zeros(SampleSize, "like", x); - sensitive_rows = [9]; - nonsensitive_rows = [1,10,11,12]; + sensitive_rows = [20]; + nonsensitive_rows = [2,5,8,10,12,15,16]; % Flip the sensitive attribute - if x(sensitive_rows) == 1 - x(sensitive_rows) = 0; - else - x(sensitive_rows) = 1; + if epsilon ~= -1 + if x(sensitive_rows) == 1 + x(sensitive_rows) = 0; + else + x(sensitive_rows) = 1; + end end - + % Apply epsilon perturbation to non-sensitive numerical features for i = 1:length(nonsensitive_rows) - if nonsensitive_rows(i) <= size(x, 1) - disturbance(nonsensitive_rows(i), :) = epsilon; - else - error('The input data does not have enough rows.'); + if epsilon ~= -1 + if nonsensitive_rows(i) <= size(x, 1) + disturbance(nonsensitive_rows(i), :) = epsilon; + else + error('The input data does not have enough rows.'); + end end end @@ -211,4 +234,3 @@ ub = min(x + disturbance, max_values); IS = ImageStar(single(lb), single(ub)); % default: single (assume onnx input models) end - diff --git a/code/nnv/examples/Submission/ICAIF24/results/paper_results/adult_verify_debiased_results_20241008_213113.csv b/code/nnv/examples/Submission/ICAIF24/results/paper_results/adult_verify_debiased_results_20241008_213113.csv new file mode 100644 index 0000000000..37b23850c3 --- /dev/null +++ b/code/nnv/examples/Submission/ICAIF24/results/paper_results/adult_verify_debiased_results_20241008_213113.csv @@ -0,0 +1,19 @@ +Model,Epsilon,FairPercent,NonFairPercent,UnknownPercent,TotalTime,AvgTime +AC-1.onnx,0.000000,88.000000,12.000000,0.000000,0.708526,0.007085 +AC-1.onnx,0.020000,82.000000,18.000000,0.000000,1.032243,0.010322 +AC-1.onnx,0.030000,69.000000,31.000000,0.000000,1.219554,0.012196 +AC-1.onnx,0.050000,58.000000,42.000000,0.000000,1.588040,0.015880 +AC-1.onnx,0.070000,41.000000,59.000000,0.000000,2.171194,0.021712 +AC-1.onnx,0.100000,14.000000,86.000000,0.000000,2.957229,0.029572 +AC-3.onnx,0.000000,91.000000,9.000000,0.000000,0.624592,0.006246 +AC-3.onnx,0.020000,84.000000,16.000000,0.000000,3.280027,0.032800 +AC-3.onnx,0.030000,77.000000,23.000000,0.000000,5.074863,0.050749 +AC-3.onnx,0.050000,61.000000,39.000000,0.000000,10.672126,0.106721 +AC-3.onnx,0.070000,50.000000,50.000000,0.000000,16.682630,0.166826 +AC-3.onnx,0.100000,13.000000,87.000000,0.000000,39.068776,0.390688 +AC-4.onnx,0.000000,91.000000,9.000000,0.000000,0.690791,0.006908 +AC-4.onnx,0.020000,80.000000,20.000000,0.000000,5.261745,0.052617 +AC-4.onnx,0.030000,75.000000,25.000000,0.000000,11.272107,0.112721 +AC-4.onnx,0.050000,61.000000,39.000000,0.000000,41.112930,0.411129 +AC-4.onnx,0.070000,37.000000,63.000000,0.000000,106.287926,1.062879 +AC-4.onnx,0.100000,4.000000,96.000000,0.000000,306.876634,3.068766 diff --git a/code/nnv/examples/Submission/ICAIF24/results/paper_results/adult_verify_results_20241008_212021.csv b/code/nnv/examples/Submission/ICAIF24/results/paper_results/adult_verify_results_20241008_212021.csv new file mode 100644 index 0000000000..12972dea04 --- /dev/null +++ b/code/nnv/examples/Submission/ICAIF24/results/paper_results/adult_verify_results_20241008_212021.csv @@ -0,0 +1,19 @@ +Model,Epsilon,FairPercent,NonFairPercent,UnknownPercent,TotalTime,AvgTime +AC-1.onnx,0.000000,89.000000,11.000000,0.000000,0.597936,0.005979 +AC-1.onnx,0.020000,84.000000,16.000000,0.000000,0.752556,0.007526 +AC-1.onnx,0.030000,81.000000,19.000000,0.000000,0.891781,0.008918 +AC-1.onnx,0.050000,69.000000,31.000000,0.000000,1.250838,0.012508 +AC-1.onnx,0.070000,50.000000,50.000000,0.000000,1.697729,0.016977 +AC-1.onnx,0.100000,22.000000,78.000000,0.000000,2.771931,0.027719 +AC-3.onnx,0.000000,87.000000,13.000000,0.000000,0.483064,0.004831 +AC-3.onnx,0.020000,84.000000,16.000000,0.000000,2.467884,0.024679 +AC-3.onnx,0.030000,82.000000,18.000000,0.000000,4.043998,0.040440 +AC-3.onnx,0.050000,71.000000,29.000000,0.000000,8.457965,0.084580 +AC-3.onnx,0.070000,50.000000,50.000000,0.000000,16.411845,0.164118 +AC-3.onnx,0.100000,27.000000,73.000000,0.000000,41.628040,0.416280 +AC-4.onnx,0.000000,88.000000,12.000000,0.000000,0.633633,0.006336 +AC-4.onnx,0.020000,83.000000,17.000000,0.000000,3.925292,0.039253 +AC-4.onnx,0.030000,79.000000,21.000000,0.000000,8.023037,0.080230 +AC-4.onnx,0.050000,71.000000,29.000000,0.000000,33.094677,0.330947 +AC-4.onnx,0.070000,43.000000,57.000000,0.000000,82.344672,0.823447 +AC-4.onnx,0.100000,4.000000,65.000000,31.000000,163.138754,1.631388 diff --git a/code/nnv/examples/Submission/ICAIF24/results/paper_results/bank_verify_results_20241008_215459.csv b/code/nnv/examples/Submission/ICAIF24/results/paper_results/bank_verify_results_20241008_215459.csv new file mode 100644 index 0000000000..6cfa2ebcd7 --- /dev/null +++ b/code/nnv/examples/Submission/ICAIF24/results/paper_results/bank_verify_results_20241008_215459.csv @@ -0,0 +1,19 @@ +Model,Epsilon,FairPercent,NonFairPercent,UnknownPercent,TotalTime,AvgTime +BM-5.onnx,0.000000,89.000000,11.000000,0.000000,0.693553,0.006936 +BM-5.onnx,0.020000,87.000000,13.000000,0.000000,0.852783,0.008528 +BM-5.onnx,0.030000,85.000000,15.000000,0.000000,0.968930,0.009689 +BM-5.onnx,0.050000,85.000000,15.000000,0.000000,1.243363,0.012434 +BM-5.onnx,0.070000,85.000000,15.000000,0.000000,1.581434,0.015814 +BM-5.onnx,0.100000,85.000000,15.000000,0.000000,2.129463,0.021295 +BM-6.onnx,0.000000,85.000000,15.000000,0.000000,0.645633,0.006456 +BM-6.onnx,0.020000,85.000000,15.000000,0.000000,0.690572,0.006906 +BM-6.onnx,0.030000,85.000000,15.000000,0.000000,0.741724,0.007417 +BM-6.onnx,0.050000,84.000000,16.000000,0.000000,0.820572,0.008206 +BM-6.onnx,0.070000,83.000000,17.000000,0.000000,0.927170,0.009272 +BM-6.onnx,0.100000,82.000000,18.000000,0.000000,1.002001,0.010020 +BM-7.onnx,0.000000,84.000000,16.000000,0.000000,0.667004,0.006670 +BM-7.onnx,0.020000,81.000000,19.000000,0.000000,5.165707,0.051657 +BM-7.onnx,0.030000,81.000000,19.000000,0.000000,12.963960,0.129640 +BM-7.onnx,0.050000,81.000000,19.000000,0.000000,43.403476,0.434035 +BM-7.onnx,0.070000,79.000000,21.000000,0.000000,108.483197,1.084832 +BM-7.onnx,0.100000,79.000000,21.000000,0.000000,395.816458,3.958165 diff --git a/code/nnv/examples/Submission/ICAIF24/results/paper_results/german_verify_results_20241008_214414.csv b/code/nnv/examples/Submission/ICAIF24/results/paper_results/german_verify_results_20241008_214414.csv new file mode 100644 index 0000000000..a7f469a481 --- /dev/null +++ b/code/nnv/examples/Submission/ICAIF24/results/paper_results/german_verify_results_20241008_214414.csv @@ -0,0 +1,19 @@ +Model,Epsilon,FairPercent,NonFairPercent,UnknownPercent,TotalTime,AvgTime +GC-1.onnx,0.000000,74.000000,26.000000,0.000000,0.726445,0.007264 +GC-1.onnx,0.020000,68.000000,32.000000,0.000000,1.792372,0.017924 +GC-1.onnx,0.030000,66.000000,34.000000,0.000000,3.178889,0.031789 +GC-1.onnx,0.050000,61.000000,39.000000,0.000000,6.203132,0.062031 +GC-1.onnx,0.070000,58.000000,42.000000,0.000000,12.992835,0.129928 +GC-1.onnx,0.100000,55.000000,45.000000,0.000000,30.632319,0.306323 +GC-2.onnx,0.000000,77.000000,23.000000,0.000000,0.704331,0.007043 +GC-2.onnx,0.020000,73.000000,27.000000,0.000000,4.499306,0.044993 +GC-2.onnx,0.030000,72.000000,28.000000,0.000000,8.998774,0.089988 +GC-2.onnx,0.050000,69.000000,31.000000,0.000000,35.603197,0.356032 +GC-2.onnx,0.070000,64.000000,36.000000,0.000000,116.153880,1.161539 +GC-2.onnx,0.100000,57.000000,43.000000,0.000000,511.699040,5.116990 +GC-3.onnx,0.000000,74.000000,26.000000,0.000000,0.510964,0.005110 +GC-3.onnx,0.020000,70.000000,30.000000,0.000000,0.547172,0.005472 +GC-3.onnx,0.030000,69.000000,31.000000,0.000000,0.582756,0.005828 +GC-3.onnx,0.050000,62.000000,38.000000,0.000000,0.624272,0.006243 +GC-3.onnx,0.070000,58.000000,42.000000,0.000000,0.686193,0.006862 +GC-3.onnx,0.100000,57.000000,43.000000,0.000000,0.755054,0.007551 diff --git a/code/nnv/examples/NN/FairNNV/getCounterRegion.m b/code/nnv/examples/Submission/ICAIF24/workshopping/getCounterRegion.m similarity index 100% rename from code/nnv/examples/NN/FairNNV/getCounterRegion.m rename to code/nnv/examples/Submission/ICAIF24/workshopping/getCounterRegion.m