From c7bd6b602f32c1fa4ae9e9036c6b74fe10bf60d2 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Fri, 22 Mar 2019 02:53:39 -0400
Subject: [PATCH 01/40] genotypes.py random path
---
cnn/genotypes.py | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index 66f733b..aed50b9 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -273,3 +273,28 @@
MULTI_CHANNEL_GREEDY_SCALAR_BOTTOM_UP = ['Source', 'Conv3x3_2', 'BatchNorm_2', 'layer_0_stride_1_c_in_128_c_out_256_op_type_SharpSepConv', 'layer_0_add_c_out_256_stride_1', 'layer_0_stride_2_c_in_256_c_out_32_op_type_ResizablePool', 'layer_0_add_c_out_32_stride_2', 'layer_1_stride_1_c_in_32_c_out_32_op_type_ResizablePool', 'layer_1_add_c_out_32_stride_1', 'layer_1_stride_2_c_in_32_c_out_32_op_type_ResizablePool', 'layer_1_add_c_out_32_stride_2', 'layer_2_stride_1_c_in_32_c_out_256_op_type_ResizablePool', 'layer_2_add_c_out_256_stride_1', 'layer_2_stride_2_c_in_256_c_out_256_op_type_ResizablePool', 'layer_2_add_c_out_256_stride_2', 'layer_3_stride_1_c_in_256_c_out_256_op_type_ResizablePool', 'layer_3_add_c_out_256_stride_1', 'layer_3_stride_2_c_in_256_c_out_32_op_type_SharpSepConv', 'layer_3_add_c_out_32_stride_2', 'SharpSepConv32', 'add-SharpSep', 'global_pooling', 'Linear']
MULTI_CHANNEL_GREEDY_MAX_W_TOP_DOWN = ['Source', 'Conv3x3_0', 'BatchNorm_0', 'layer_0_stride_1_c_in_32_c_out_32_op_type_ResizablePool', 'layer_0_add_c_out_32_stride_1', 'layer_0_stride_2_c_in_32_c_out_128_op_type_SharpSepConv', 'layer_0_add_c_out_128_stride_2', 'layer_1_stride_1_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_1_add_c_out_128_stride_1', 'layer_1_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_1_add_c_out_128_stride_2', 'layer_2_stride_1_c_in_128_c_out_64_op_type_SharpSepConv', 'layer_2_add_c_out_64_stride_1', 'layer_2_stride_2_c_in_64_c_out_64_op_type_SharpSepConv', 'layer_2_add_c_out_64_stride_2', 'layer_3_stride_1_c_in_64_c_out_128_op_type_SharpSepConv', 'layer_3_add_c_out_128_stride_1', 'layer_3_stride_2_c_in_128_c_out_128_op_type_ResizablePool', 'layer_3_add_c_out_128_stride_2', 'SharpSepConv128', 'add-SharpSep', 'global_pooling', 'Linear']
MULTI_CHANNEL_GREEDY_MAX_W_BOTTOM_UP = ['Source', 'Conv3x3_3', 'BatchNorm_3', 'layer_0_stride_1_c_in_256_c_out_128_op_type_ResizablePool', 'layer_0_add_c_out_128_stride_1', 'layer_0_stride_2_c_in_128_c_out_256_op_type_ResizablePool', 'layer_0_add_c_out_256_stride_2', 'layer_1_stride_1_c_in_256_c_out_128_op_type_ResizablePool', 'layer_1_add_c_out_128_stride_1', 'layer_1_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_1_add_c_out_128_stride_2', 'layer_2_stride_1_c_in_128_c_out_64_op_type_ResizablePool', 'layer_2_add_c_out_64_stride_1', 'layer_2_stride_2_c_in_64_c_out_64_op_type_ResizablePool', 'layer_2_add_c_out_64_stride_2', 'layer_3_stride_1_c_in_64_c_out_64_op_type_ResizablePool', 'layer_3_add_c_out_64_stride_1', 'layer_3_stride_2_c_in_64_c_out_64_op_type_ResizablePool', 'layer_3_add_c_out_64_stride_2', 'SharpSepConv64', 'add-SharpSep', 'global_pooling', 'Linear']
+MULTI_CHANNEL_RANDOM_PATH = ['Conv3x3_1', 'BatchNorm_1', 'layer_0_stride_1_c_in_64_c_out_128_op_type_ResizablePool', 'layer_0_add_c_out_128_stride_1', 'layer_0_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_0_add_c_out_128_stride_2', 'layer_1_stride_1_c_in_128_c_out_256_op_type_ResizablePool', 'layer_1_add_c_out_256_stride_1', 'layer_1_stride_2_c_in_256_c_out_256_op_type_SharpSepConv', 'layer_1_add_c_out_256_stride_2', 'layer_2_stride_1_c_in_256_c_out_128_op_type_SharpSepConv', 'layer_2_add_c_out_128_stride_1', 'layer_2_stride_2_c_in_128_c_out_32_op_type_SharpSepConv', 'layer_2_add_c_out_32_stride_2', 'layer_3_stride_1_c_in_32_c_out_64_op_type_ResizablePool', 'layer_3_add_c_out_64_stride_1', 'layer_3_stride_2_c_in_64_c_out_32_op_type_SharpSepConv', 'layer_3_add_c_out_32_stride_2', 'SharpSepConv32', 'add-SharpSep', 'global_pooling', 'Linear']
+
+# costar@ubuntu|~/src/sharpDARTS/cnn on multi_channel_search!?
+# ± export CUDA_VISIBLE_DEVICES="0" && python3 train_search.py --dataset cifar10 --batch_size 48 --layers_of_cells 8 --layers_in_cells 4 --save max_w_SharpSepConvDARTS_SEARCH_`git rev-parse --short HEAD` --init_channels
+# 16 --epochs 120 --cutout --autoaugment --seed 22 --weighting_algorithm max_w --primitives DARTS_PRIMITIVES
+# Tensorflow is not installed. Skipping tf related imports
+# Experiment dir : search-20190321-024555-max_w_SharpSepConvDARTS_SEARCH_5e49783-cifar10-DARTS_PRIMITIVES-OPS-0
+# 2019_03_21_19_11_44 epoch, 47, train_acc, 76.215997, valid_acc, 74.855997, train_loss, 0.687799, valid_loss, 0.734363, lr, 1.580315e-02, best_epoch, 47, best_valid_acc, 74.855997
+# 2019_03_21_19_11_44 genotype =
+# 2019_03_21_19_11_44 alphas_normal = tensor([[0.1134, 0.0945, 0.0894, 0.1007, 0.1466, 0.1334, 0.1964, 0.1256],
+# [0.1214, 0.0983, 0.1000, 0.1072, 0.1675, 0.1383, 0.1167, 0.1507],
+# [0.1251, 0.1066, 0.1043, 0.1674, 0.1295, 0.1237, 0.1209, 0.1225],
+# [0.1238, 0.1066, 0.1054, 0.1108, 0.1331, 0.1418, 0.1145, 0.1641],
+# [0.1009, 0.0843, 0.0801, 0.0802, 0.2970, 0.1168, 0.1329, 0.1078],
+# [0.1257, 0.1115, 0.1087, 0.1158, 0.1641, 0.1312, 0.1305, 0.1125],
+# [0.1662, 0.1154, 0.1152, 0.1194, 0.1234, 0.1248, 0.1222, 0.1134],
+# [0.1177, 0.0943, 0.1892, 0.0836, 0.1285, 0.1317, 0.1286, 0.1263],
+# [0.3851, 0.0835, 0.0718, 0.0554, 0.1031, 0.1047, 0.1011, 0.0953],
+# [0.1249, 0.1119, 0.1096, 0.1156, 0.1284, 0.1177, 0.1157, 0.1762],
+# [0.1249, 0.1186, 0.1197, 0.1244, 0.1254, 0.1319, 0.1238, 0.1312],
+# [0.1126, 0.0932, 0.2448, 0.0838, 0.1132, 0.1141, 0.1263, 0.1120],
+# [0.0791, 0.4590, 0.0665, 0.0518, 0.0843, 0.0804, 0.0846, 0.0944],
+# [0.0715, 0.0665, 0.4912, 0.0401, 0.0822, 0.0816, 0.0888, 0.0780]],
+# device='cuda:0', grad_fn=)
+SHARPSEPCONV_DARTS_MAX_W = Genotype(normal=[('dil_conv_3x3', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 2), ('skip_connect', 0), ('avg_pool_3x3', 2), ('sep_conv_3x3', 0), ('avg_pool_3x3', 4), ('max_pool_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('dil_conv_5x5', 2), ('sep_conv_5x5', 0), ('sep_conv_5x5', 0), ('sep_conv_3x3', 2), ('dil_conv_3x3', 0), ('dil_conv_5x5', 3)], reduce_concat=range(2, 6), layout='cell')
\ No newline at end of file
From 5c5c8664f8c0f2f1b7a5fd93dae3493d7d399211 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Fri, 22 Mar 2019 02:53:56 -0400
Subject: [PATCH 02/40] train.py add flops_shape
---
cnn/train.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/cnn/train.py b/cnn/train.py
index 37692cd..7da376a 100644
--- a/cnn/train.py
+++ b/cnn/train.py
@@ -140,6 +140,7 @@ def main():
cnn_model = MultiChannelNetwork(
args.init_channels, DATASET_CLASSES, layers=args.layers_of_cells, criterion=criterion, steps=args.layers_in_cells,
weighting_algorithm=args.weighting_algorithm, genotype=genotype)
+ flops_shape = [1, 3, 32, 32]
elif args.dataset == 'imagenet':
cnn_model = NetworkImageNet(args.init_channels, DATASET_CLASSES, args.layers, args.auxiliary, genotype, op_dict=op_dict, C_mid=args.mid_channels)
flops_shape = [1, 3, 224, 224]
From 65a2a20ec0d04a81167a49035d490f00e7cb3f89 Mon Sep 17 00:00:00 2001
From: Priyanka Hubli
Date: Sat, 6 Apr 2019 15:43:50 -0400
Subject: [PATCH 03/40] added new feature-mode:time_difference_images to
classify time intervals between 2 frames
---
cnn/dataset.py | 6 +-
cnn/model.py | 112 +++++++++++++++++++++++++++++++++++
cnn/train_costar.py | 138 +++++++++++++++++++++++++++-----------------
3 files changed, 201 insertions(+), 55 deletions(-)
diff --git a/cnn/dataset.py b/cnn/dataset.py
index df9f6fd..2101000 100644
--- a/cnn/dataset.py
+++ b/cnn/dataset.py
@@ -83,13 +83,15 @@
costar_class_dict = {'translation_only': 3,
'rotation_only': 5,
- 'all_features': 8}
+ 'all_features': 8,
+ 'time_difference_images': 6}
costar_supercube_inp_channel_dict = {'translation_only': 52,
'rotation_only': 55,
'all_features': 57}
costar_vec_size_dict = {'translation_only': 44,
'rotation_only': 49,
- 'all_features': 49}
+ 'all_features': 49,
+ 'time_difference_images': 0}
COSTAR_SET_NAMES = ['blocks_only', 'blocks_with_plush_toy']
COSTAR_SUBSET_NAMES = ['success_only', 'error_failure_only', 'task_failure_only', 'task_and_error_failure']
diff --git a/cnn/model.py b/cnn/model.py
index 31df53c..413c4d5 100644
--- a/cnn/model.py
+++ b/cnn/model.py
@@ -509,3 +509,115 @@ def forward(self, input, log=False):
def reset_noise(self):
self.classifier.reset_noise()
+
+class residual_block(nn.Module):
+ """Implements a layer of ResNeXt.
+
+ Based in https://blog.waya.ai/deep-residual-learning-9610bb62c355.
+
+ Args:
+ input: Input for the block.
+ channels_in: Number of channels of data for the convolutional group.
+ channels_out: Number of chhannels generated as output.
+ cardinality: Number of convolution groups. Must be divisible by channels_in
+ is_training: Placeholder that indicates if the model is being trained
+ strides: Strides.
+ project_shortcut: Indicates whether the input should be projected to match the output's dimensions.
+
+ Returns:
+ A tensor with shape (-1, channels_out, width, height).
+
+ """
+ def __init__(self, channels_in, channels_out, cardinality, strides=(1, 1), project_shortcut=False):
+ super(residual_block, self).__init__()
+ self.channels_in = channels_in
+ self.channels_out = channels_out
+ self.cardinality = cardinality
+ self.project_shortcut = project_shortcut
+ self.strides = strides
+
+ self.conv1 = nn.Conv2d(64, self.channels_in, 1 , stride = 1)
+ self.norm1 = nn.BatchNorm2d(self.channels_in)
+ self.group_conv = nn.Conv2d(self.channels_in, self.channels_in, kernel_size=(3,3),stride=self.strides, groups=1,padding=1)
+
+ self.norm2 = nn.BatchNorm2d(self.channels_in)
+ self.conv2 = nn.Conv2d(self.channels_in ,self.channels_out, 1 , stride = 1)
+ self.norm3 = nn.BatchNorm2d(self.channels_out)
+
+ if self.project_shortcut or self.strides != (1,1):
+ self.conv3 = nn.Conv2d(64, self.channels_out, 1, stride = self.strides)
+ self.norm4 = nn.BatchNorm2d(self.channels_out)
+
+ def forward(self, input):
+ shortcut = input
+ x = F.relu(self.norm1(self.conv1(input)))
+ x = self.group_conv(x)
+ x = F.relu(self.norm2(x))
+ x = self.norm3(self.conv2(x))
+
+ if self.project_shortcut or self.strides!=(1,1):
+ # When the dimensions increase projection shortcut is used to match dimensions (done by 1×1 convolutions).
+ shortcut = self.norm4(self.conv3(shortcut))
+
+ output = F.relu(torch.add(shortcut, x))
+ return output
+
+class TDCFeaturizer(nn.Module):
+ """Temporal Distance Classification featurizer
+
+ Reference: "Playing hard exploration games by watching YouTube"
+ The task consists of presenting the network with 2 frames separated by n timesteps,
+ and making it classify the distance between the frames.
+
+ We use the same network architecture as the paper:
+ 3 convolutional layers, followed by 3 residual blocks,
+ followed by 2 fully connected layers for the encoder.
+
+ For the classifier, we do a multiplication between both feature vectors
+ followed by a fully connected layer.
+
+ """
+ def __init__(self):
+ super(TDCFeaturizer, self).__init__()
+ self.feature_vector_size = 1024
+
+ self.conv1 = nn.Conv2d(3, 32, 3, stride = 2, padding=1)
+ self.conv2 = nn.Conv2d(32, 64, 3, stride = 1,padding=1)
+ self.conv3 = nn.Conv2d(64, 64, 3, stride = 1,padding=1)
+ self.pool = nn.MaxPool2d(2, 2)
+ self.norm1 = nn.BatchNorm2d(32)
+ self.norm2 = nn.BatchNorm2d(64)
+ self.norm3 = nn.BatchNorm2d(64)
+ self.residual_block = residual_block(64, 64, 1)
+ self.fc1 = nn.Linear(3072, self.feature_vector_size) #dense layer
+ self.fc2 = nn.Linear(self.feature_vector_size, self.feature_vector_size)
+ self.fc3 = nn.Linear(1024, self.feature_vector_size)
+ self.fc4 = nn.Linear(self.feature_vector_size, 6) # size of each label
+
+
+ def forward(self, img_1, img_2):
+ logits_aux = None
+ x = torch.cat((img_1,img_2),0)
+ x = self.pool(self.norm1(F.relu(self.conv1(x))))
+ x = self.pool(self.norm2(F.relu(self.conv2(x))))
+ x = self.pool(self.norm3(F.relu(self.conv3(x))))
+
+ for i in range(3):
+ x = self.residual_block(x)
+
+ x = x.view(-1, 3072) # flatten layer (3072 = 64*6*8)
+ x = F.relu(self.fc1(x))
+
+ feature_vector = self.fc2(x)
+ feature_vector = F.normalize(feature_vector, p=2, dim=1)
+ #if not self.training:
+ # return feature_vector
+ feature_vector_stack = feature_vector.view(-1, 2, self.feature_vector_size)
+
+ combined_embeddings = torch.mul(feature_vector_stack[:, 0, :], feature_vector_stack[:, 1, :])
+
+ x = F.relu(self.fc3(combined_embeddings))
+ prediction = F.relu(self.fc4(x))
+
+ return prediction, logits_aux
+
diff --git a/cnn/train_costar.py b/cnn/train_costar.py
index bdc4aef..fb8ac60 100644
--- a/cnn/train_costar.py
+++ b/cnn/train_costar.py
@@ -33,6 +33,7 @@
import torchvision.datasets as datasets
import torchvision.models as models
import torchvision
+from model import TDCFeaturizer
import numpy as np
import random
@@ -70,6 +71,7 @@
# choices=model_names,
help='model architecture: ' +
' | '.join(model_names) +
+ 'TDCFeaturizer for feature embeddings'
' (default: SHARP_DARTS)')
parser.add_argument('-j', '--workers', default=4, type=int, metavar='N',
help='number of data loading workers (default: 4)')
@@ -146,7 +148,7 @@
help='which subset to use in the CoSTAR BSD. Options are "success_only", '
'"error_failure_only", "task_failure_only", or "task_and_error_failure". Defaults to "success_only"')
parser.add_argument('--feature_mode', type=str, default='all_features',
- help='which feature mode to use. Options are "translation_only", "rotation_only", "stacking_reward", '
+ help='which feature mode to use. Options are "translation_only", "rotation_only", "stacking_reward", "time_difference_images"'
'or the default "all_features"')
parser.add_argument('--num_images_per_example', type=int, default=200,
help='Number of times an example is visited per epoch. Default value is 200. Since the image for each visit to an '
@@ -168,7 +170,7 @@
best_combined_error = float('inf')
args = parser.parse_args()
logger = None
-
+model_input_shape = (224,224,3) # default input shape of images
VECTOR_SIZE = dataset.costar_vec_size_dict[args.feature_mode]
def fast_collate(batch):
@@ -204,7 +206,7 @@ def main():
# note the gpu is used for directory creation and log files
# which is needed when run as multiple processes
args = utils.initialize_files_and_args(args)
- logger = utils.logging_setup(args.log_file_path)
+ logger = utils.logging_setup(args.log_file_path)
# # load the correct ops dictionary
op_dict_to_load = "operations.%s" % args.ops
@@ -222,13 +224,16 @@ def main():
if args.arch == 'NetworkResNetCOSTAR':
# baseline model for comparison
model = NetworkResNetCOSTAR(args.init_channels, classes, args.layers, args.auxiliary, None, vector_size=VECTOR_SIZE, op_dict=op_dict, C_mid=args.mid_channels)
+ model.drop_path_prob = 0.0
+ elif args.arch == 'TDCFeaturizer':
+ model = TDCFeaturizer()
else:
# create model
genotype = eval("genotypes.%s" % args.arch)
# create the neural network
model = NetworkCOSTAR(args.init_channels, classes, args.layers, args.auxiliary, genotype, vector_size=VECTOR_SIZE, op_dict=op_dict, C_mid=args.mid_channels)
- model.drop_path_prob = 0.0
+ model.drop_path_prob = 0.0
# if args.pretrained:
# logger.info("=> using pre-trained model '{}'".format(args.arch))
# model = models.__dict__[args.arch](pretrained=True)
@@ -248,19 +253,28 @@ def main():
# model = DDP(model)
# delay_allreduce delays all communication to the end of the backward pass.
model = DDP(model, delay_allreduce=True)
-
- # define loss function (criterion) and optimizer
- criterion = nn.MSELoss().cuda()
- # NOTE(rexxarchl): MSLE loss, indicated as better for rotation in costar_hyper/costar_block_stacking_train_regression.py
- # is not available in PyTorch by default
-
+
+
# Scale learning rate based on global batch size
args.learning_rate = args.learning_rate * float(args.batch_size * args.world_size)/256.
init_lr = args.learning_rate / args.warmup_lr_divisor
- optimizer = torch.optim.SGD(model.parameters(), init_lr,
- momentum=args.momentum,
- weight_decay=args.weight_decay)
+ # define loss function (criterion) and optimizer
+ if args.feature_mode == 'time_difference_images':
+ # 'time_difference_images' is a feature mode where we try to classify time intervals between two frames.
+ criterion = nn.CrossEntropyLoss().cuda()
+ optimizer = torch.optim.Adam(model.parameters(), lr=init_lr)
+ # Change collate function and model input shape for this feature mode
+ fast_collate = torch.utils.data.dataloader.default_collate
+ model_input_shape = (3,96,128)
+ else:
+ criterion = nn.MSELoss().cuda()
+ # NOTE(rexxarchl): MSLE loss, indicated as better for rotation in costar_hyper/costar_block_stacking_train_regression.py
+ # is not available in PyTorch by default
+ optimizer = torch.optim.SGD(model.parameters(), init_lr,
+ momentum=args.momentum,
+ weight_decay=args.weight_decay)
+
# epoch_count = args.epochs - args.start_epoch
# scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, float(epoch_count))
# scheduler = warmup_scheduler.GradualWarmupScheduler(
@@ -307,21 +321,20 @@ def resume():
num_workers=args.workers,
costar_set_name=args.set_name, costar_subset_name=args.subset_name,
costar_feature_mode=args.feature_mode, costar_version=args.version, costar_num_images_per_example=args.num_images_per_example,
- costar_output_shape=(224, 224, 3), costar_random_augmentation=None, costar_one_hot_encoding=True, evaluate=evaluate)
-
+ costar_output_shape=model_input_shape, costar_random_augmentation=None, costar_one_hot_encoding=True, evaluate=evaluate)
if args.evaluate:
# Load the test set
test_loader = dataset.get_costar_test_queue(
args.data, costar_set_name=args.set_name, costar_subset_name=args.subset_name, collate_fn=fast_collate,
costar_feature_mode=args.feature_mode, costar_version=args.version, costar_num_images_per_example=args.num_images_per_example,
- costar_output_shape=(224, 224, 3), costar_random_augmentation=None, costar_one_hot_encoding=True)
-
+ costar_output_shape=model_input_shape, costar_random_augmentation=None, costar_one_hot_encoding=True)
+
# Evaluate on all splits, without any augmentation
validate(train_loader, model, criterion, args, prefix='evaluate_train_')
validate(val_loader, model, criterion, args, prefix='evaluate_val_')
validate(test_loader, model, criterion, args, prefix='evaluate_test_')
return
-
+
lr_schedule = cosine_power_annealing(
epochs=args.epochs, max_lr=args.learning_rate, min_lr=args.learning_rate_min,
warmup_epochs=args.warmup_epochs, exponent_order=args.lr_power_annealing_exponent_order,
@@ -345,7 +358,8 @@ def resume():
for param_group in optimizer.param_groups:
param_group['lr'] = learning_rate
# scheduler.step()
- model.drop_path_prob = args.drop_path_prob * float(epoch) / float(args.epochs)
+ if args.feature_mode != 'time_difference_images':
+ model.drop_path_prob = args.drop_path_prob * float(epoch) / float(args.epochs)
# train for one epoch
train_stats = train(train_loader, model, criterion, optimizer, int(epoch), args)
if args.prof:
@@ -416,13 +430,13 @@ def resume():
num_workers=args.workers,
costar_set_name=args.set_name, costar_subset_name=args.subset_name,
costar_feature_mode=args.feature_mode, costar_version=args.version, costar_num_images_per_example=args.num_images_per_example,
- costar_output_shape=(224, 224, 3), costar_random_augmentation=None, costar_one_hot_encoding=True, evaluate=evaluate)
+ costar_output_shape=model_input_shape, costar_random_augmentation=None, costar_one_hot_encoding=True, evaluate=evaluate)
# Get the test set
test_loader = dataset.get_costar_test_queue(
args.data, costar_set_name=args.set_name, costar_subset_name=args.subset_name, collate_fn=fast_collate,
costar_feature_mode=args.feature_mode, costar_version=args.version, costar_num_images_per_example=args.num_images_per_example,
- costar_output_shape=(224, 224, 3), costar_random_augmentation=None, costar_one_hot_encoding=True)
+ costar_output_shape=model_input_shape, costar_random_augmentation=None, costar_one_hot_encoding=True)
# Evaluate on all splits, without any augmentation
validate(train_loader, model, criterion, args, prefix='best_final_train_')
@@ -430,7 +444,7 @@ def resume():
validate(test_loader, model, criterion, args, prefix='best_final_test_')
logger.info("Final evaluation complete! Save dir: ' + str(args.save)")
-
+
class data_prefetcher():
def __init__(self, loader, cutout=False, cutout_length=112, cutout_cuts=1):
self.loader = iter(loader)
@@ -487,6 +501,8 @@ def train(train_loader, model, criterion, optimizer, epoch, args):
cart_error, angle_error = [], []
input_img, input_vec, target = prefetcher.next()
+ if args.feature_mode == 'time_difference_images':
+ target = target.type(torch.cuda.LongTensor)
batch_size = input_img.size(0)
i = -1
if args.local_rank == 0:
@@ -507,7 +523,8 @@ def train(train_loader, model, criterion, optimizer, epoch, args):
# compute output
# note here the term output is equivalent to logits
output, logits_aux = model(input_img, input_vec)
- output = sigmoid(output)
+ if args.feature_mode != 'time_difference_images':
+ output = sigmoid(output)
loss = criterion(output, target)
if logits_aux is not None and args.auxiliary:
logits_aux = sigmoid(logits_aux)
@@ -515,24 +532,29 @@ def train(train_loader, model, criterion, optimizer, epoch, args):
loss += args.auxiliary_weight * loss_aux
# measure accuracy and record loss
- with torch.no_grad():
- output_np = output.cpu().detach().numpy()
- target_np = target.cpu().detach().numpy()
- batch_abs_cart_distance, batch_abs_angle_distance = accuracy(output_np, target_np)
- abs_cart_f, abs_angle_f = np.mean(batch_abs_cart_distance), np.mean(batch_abs_angle_distance)
- cart_error.extend(batch_abs_cart_distance)
- angle_error.extend(batch_abs_angle_distance)
+ if args.feature_mode != 'time_difference_images':
+ with torch.no_grad():
+ output_np = output.cpu().detach().numpy()
+ target_np = target.cpu().detach().numpy()
+ batch_abs_cart_distance, batch_abs_angle_distance = accuracy(output_np, target_np)
+ abs_cart_f, abs_angle_f = np.mean(batch_abs_cart_distance), np.mean(batch_abs_angle_distance)
+ cart_error.extend(batch_abs_cart_distance)
+ angle_error.extend(batch_abs_angle_distance)
+
+ if args.distributed:
+ reduced_loss = reduce_tensor(loss.data)
+ abs_cart_f = reduce_tensor(abs_cart_f)
+ abs_angle_f = reduce_tensor(abs_angle_f)
+ else:
+ reduced_loss = loss.data
- if args.distributed:
- reduced_loss = reduce_tensor(loss.data)
- abs_cart_f = reduce_tensor(abs_cart_f)
- abs_angle_f = reduce_tensor(abs_angle_f)
+ losses.update(reduced_loss, batch_size)
+ abs_cart_m.update(abs_cart_f, batch_size)
+ abs_angle_m.update(abs_angle_f, batch_size)
+
else:
- reduced_loss = loss.data
-
- losses.update(reduced_loss, batch_size)
- abs_cart_m.update(abs_cart_f, batch_size)
- abs_angle_m.update(abs_angle_f, batch_size)
+ reduced_loss = reduce_tensor(loss.data) if args.distributed else loss.data
+ losses.update(reduced_loss)
# compute gradient and do SGD step
optimizer.zero_grad()
@@ -545,6 +567,8 @@ def train(train_loader, model, criterion, optimizer, epoch, args):
end = time.time()
input_img, input_vec, target = prefetcher.next()
+ if args.feature_mode == 'time_difference_images' and target is not None:
+ target = target.type(torch.cuda.LongTensor)
if args.local_rank == 0:
progbar.update()
@@ -614,6 +638,8 @@ def validate(val_loader, model, criterion, args, prefix='val_'):
cart_error, angle_error = [], []
prefetcher = data_prefetcher(val_loader)
input_img, input_vec, target = prefetcher.next()
+ if args.feature_mode == 'time_difference_images':
+ target = target.type(torch.cuda.LongTensor)
batch_size = input_img.size(0)
i = -1
if args.local_rank == 0:
@@ -634,21 +660,25 @@ def validate(val_loader, model, criterion, args, prefix='val_'):
loss = criterion(output, target)
# measure accuracy and record loss
- batch_abs_cart_distance, batch_abs_angle_distance = accuracy(output.data.cpu().numpy(), target.data.cpu().numpy())
- abs_cart_f, abs_angle_f = np.mean(batch_abs_cart_distance), np.mean(batch_abs_angle_distance)
- cart_error.extend(batch_abs_cart_distance)
- angle_error.extend(batch_abs_angle_distance)
-
- if args.distributed:
- reduced_loss = reduce_tensor(loss.data)
- abs_cart_f = reduce_tensor(abs_cart_f)
- abs_angle_f = reduce_tensor(abs_angle_f)
- else:
- reduced_loss = loss.data
+ if args.feature_mode != 'time_difference_images':
+ batch_abs_cart_distance, batch_abs_angle_distance = accuracy(output.data.cpu().numpy(), target.data.cpu().numpy())
+ abs_cart_f, abs_angle_f = np.mean(batch_abs_cart_distance), np.mean(batch_abs_angle_distance)
+ cart_error.extend(batch_abs_cart_distance)
+ angle_error.extend(batch_abs_angle_distance)
- losses.update(reduced_loss, batch_size)
- abs_cart_m.update(abs_cart_f, batch_size)
- abs_angle_m.update(abs_angle_f, batch_size)
+ if args.distributed:
+ reduced_loss = reduce_tensor(loss.data)
+ abs_cart_f = reduce_tensor(abs_cart_f)
+ abs_angle_f = reduce_tensor(abs_angle_f)
+ else:
+ reduced_loss = loss.data
+
+ losses.update(reduced_loss, batch_size)
+ abs_cart_m.update(abs_cart_f, batch_size)
+ abs_angle_m.update(abs_angle_f, batch_size)
+ else:
+ reduced_loss = reduce_tensor(loss.data) if args.distributed else loss.data
+ losses.update(reduced_loss)
# measure elapsed time
batch_time.update(time.time() - end)
@@ -673,6 +703,8 @@ def validate(val_loader, model, criterion, args, prefix='val_'):
abs_cart=abs_cart_m, abs_angle=abs_angle_m))
input_img, input_vec, target = prefetcher.next()
+ if args.feature_mode == 'time_difference_images' and target is not None:
+ target = target.type(torch.cuda.LongTensor)
# logger.info(' * combined_error {combined_error.avg:.3f} top5 {top5.avg:.3f}'
# .format(combined_error=combined_error, top5=top5))
From a965ce06100c32f8df34842f6050dab43569806f Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:08:00 -0400
Subject: [PATCH 04/40] cnn/genotypes.py first try at sharper search space
---
cnn/genotypes.py | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index 28daa8d..c59ba96 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -21,6 +21,26 @@
'dil_choke_conv_3x3',
]
+SHARPER_PRIMITIVES = [
+ 'none',
+ 'max_pool_3x3',
+ 'avg_pool_3x3',
+ 'skip_connect',
+ 'sep_conv_3x3',
+ 'sep_conv_5x5',
+ 'sep_conv_7x7',
+ 'dil_conv_3x3',
+ 'dil_conv_5x5',
+ # 'nor_conv_3x3',
+ # 'nor_conv_5x5',
+ # 'nor_conv_7x7',
+ 'flood_conv_3x3',
+ 'flood_conv_5x5',
+ 'dil_flood_conv_3x3',
+ # 'choke_conv_3x3',
+ # 'dil_choke_conv_3x3',
+]
+
# Primitives for the original darts search space
DARTS_PRIMITIVES = [
'none',
From d9a54bf3a30fa31f423a55cadf661a34c4ff943a Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:11:35 -0400
Subject: [PATCH 05/40] cnn/visualize.py beter style params
---
cnn/visualize.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cnn/visualize.py b/cnn/visualize.py
index d768aef..d599e6c 100644
--- a/cnn/visualize.py
+++ b/cnn/visualize.py
@@ -6,8 +6,8 @@
def plot(genotype, filename):
g = Digraph(
format='pdf',
- edge_attr=dict(fontsize='20', fontname="times"),
- node_attr=dict(style='filled', shape='rect', align='center', fontsize='20', height='0.5', width='0.5', penwidth='2', fontname="times"),
+ edge_attr=dict(fontsize='32', fontname="times"),
+ node_attr=dict(style='filled', shape='rect', align='center', fontsize='32', height='0.7', width='0.7', penwidth='2', fontname="times"),
engine='dot')
g.body.extend(['rankdir=LR'])
From 284f92db9b9a79b12b71a387799b274086a6a22e Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:13:10 -0400
Subject: [PATCH 06/40] WARNING UNCLEAR CODE STATE cnn/model_search.py merge
graph search algorithms? not clear of code state
---
cnn/model_search.py | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/cnn/model_search.py b/cnn/model_search.py
index f074ddc..6176dc0 100644
--- a/cnn/model_search.py
+++ b/cnn/model_search.py
@@ -541,8 +541,47 @@ def forward(self, input_batch):
# out = self.global_pooling(out)
logits = self.classifier(out.view(out.size(0),-1))
# print('logits')
+ #print("Optimal_path_forward", nx.algorithms.dag.dag_longest_path(self.G))
+ #print("Top down greedy", self.gen_greedy_path(self.G,"top_down"))
+ #print("Bottom up greedy",self.gen_greedy_path(self.G,"bottom_up"))
return logits
+ def gen_greedy_path(self, G, strategy="top_down"):
+ if strategy == "top_down":
+ start_ = "Source"
+ current_node = "Source"
+ end_node = "Linear"
+ new_G = G
+ elif strategy == "bottom_up":
+ start_ = "Linear"
+ current_node = "Linear"
+ end_node = "Source"
+ new_G = G.reverse(copy=True)
+ wt = 0
+ node_list = []
+ while current_node != end_node:
+ neighbors = [n for n in new_G.neighbors(start_)]
+ for nodes in neighbors:
+ weight_ = new_G.get_edge_data(start_, nodes, "weight")
+ # print(weight_)
+ if len(weight_):
+ weight_ = weight_["weight"]
+ else:
+ weight_ = 0
+ # print(weight_)
+ if weight_ > wt:
+ wt = weight_
+ current_node = nodes
+ node_list.append(current_node)
+ # print("start",start_)
+ # print(node)
+ start_ = current_node
+ wt = -1
+ # print(node_list)
+ if strategy == "bottom_up":
+ node_list = node_list[::-1]
+ node_list.append("Linear")
+ return node_list
def arch_weights(self, stride_idx):
# ops are stored as layer, stride, cin, cout, num_layer_types
# while weights are ordered stride_index, layer, cin, cout, num_layer_types
From 1354bea610dae70254c410da9c8e8cd580d2efa5 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:14:16 -0400
Subject: [PATCH 07/40] WARNING UNCLEAR CODE STATE genotypes.py fixes to
multichannel hyperparameter grid search path strings
---
cnn/genotypes.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index aed50b9..ab14f6e 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -273,7 +273,8 @@
MULTI_CHANNEL_GREEDY_SCALAR_BOTTOM_UP = ['Source', 'Conv3x3_2', 'BatchNorm_2', 'layer_0_stride_1_c_in_128_c_out_256_op_type_SharpSepConv', 'layer_0_add_c_out_256_stride_1', 'layer_0_stride_2_c_in_256_c_out_32_op_type_ResizablePool', 'layer_0_add_c_out_32_stride_2', 'layer_1_stride_1_c_in_32_c_out_32_op_type_ResizablePool', 'layer_1_add_c_out_32_stride_1', 'layer_1_stride_2_c_in_32_c_out_32_op_type_ResizablePool', 'layer_1_add_c_out_32_stride_2', 'layer_2_stride_1_c_in_32_c_out_256_op_type_ResizablePool', 'layer_2_add_c_out_256_stride_1', 'layer_2_stride_2_c_in_256_c_out_256_op_type_ResizablePool', 'layer_2_add_c_out_256_stride_2', 'layer_3_stride_1_c_in_256_c_out_256_op_type_ResizablePool', 'layer_3_add_c_out_256_stride_1', 'layer_3_stride_2_c_in_256_c_out_32_op_type_SharpSepConv', 'layer_3_add_c_out_32_stride_2', 'SharpSepConv32', 'add-SharpSep', 'global_pooling', 'Linear']
MULTI_CHANNEL_GREEDY_MAX_W_TOP_DOWN = ['Source', 'Conv3x3_0', 'BatchNorm_0', 'layer_0_stride_1_c_in_32_c_out_32_op_type_ResizablePool', 'layer_0_add_c_out_32_stride_1', 'layer_0_stride_2_c_in_32_c_out_128_op_type_SharpSepConv', 'layer_0_add_c_out_128_stride_2', 'layer_1_stride_1_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_1_add_c_out_128_stride_1', 'layer_1_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_1_add_c_out_128_stride_2', 'layer_2_stride_1_c_in_128_c_out_64_op_type_SharpSepConv', 'layer_2_add_c_out_64_stride_1', 'layer_2_stride_2_c_in_64_c_out_64_op_type_SharpSepConv', 'layer_2_add_c_out_64_stride_2', 'layer_3_stride_1_c_in_64_c_out_128_op_type_SharpSepConv', 'layer_3_add_c_out_128_stride_1', 'layer_3_stride_2_c_in_128_c_out_128_op_type_ResizablePool', 'layer_3_add_c_out_128_stride_2', 'SharpSepConv128', 'add-SharpSep', 'global_pooling', 'Linear']
MULTI_CHANNEL_GREEDY_MAX_W_BOTTOM_UP = ['Source', 'Conv3x3_3', 'BatchNorm_3', 'layer_0_stride_1_c_in_256_c_out_128_op_type_ResizablePool', 'layer_0_add_c_out_128_stride_1', 'layer_0_stride_2_c_in_128_c_out_256_op_type_ResizablePool', 'layer_0_add_c_out_256_stride_2', 'layer_1_stride_1_c_in_256_c_out_128_op_type_ResizablePool', 'layer_1_add_c_out_128_stride_1', 'layer_1_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_1_add_c_out_128_stride_2', 'layer_2_stride_1_c_in_128_c_out_64_op_type_ResizablePool', 'layer_2_add_c_out_64_stride_1', 'layer_2_stride_2_c_in_64_c_out_64_op_type_ResizablePool', 'layer_2_add_c_out_64_stride_2', 'layer_3_stride_1_c_in_64_c_out_64_op_type_ResizablePool', 'layer_3_add_c_out_64_stride_1', 'layer_3_stride_2_c_in_64_c_out_64_op_type_ResizablePool', 'layer_3_add_c_out_64_stride_2', 'SharpSepConv64', 'add-SharpSep', 'global_pooling', 'Linear']
-MULTI_CHANNEL_RANDOM_PATH = ['Conv3x3_1', 'BatchNorm_1', 'layer_0_stride_1_c_in_64_c_out_128_op_type_ResizablePool', 'layer_0_add_c_out_128_stride_1', 'layer_0_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_0_add_c_out_128_stride_2', 'layer_1_stride_1_c_in_128_c_out_256_op_type_ResizablePool', 'layer_1_add_c_out_256_stride_1', 'layer_1_stride_2_c_in_256_c_out_256_op_type_SharpSepConv', 'layer_1_add_c_out_256_stride_2', 'layer_2_stride_1_c_in_256_c_out_128_op_type_SharpSepConv', 'layer_2_add_c_out_128_stride_1', 'layer_2_stride_2_c_in_128_c_out_32_op_type_SharpSepConv', 'layer_2_add_c_out_32_stride_2', 'layer_3_stride_1_c_in_32_c_out_64_op_type_ResizablePool', 'layer_3_add_c_out_64_stride_1', 'layer_3_stride_2_c_in_64_c_out_32_op_type_SharpSepConv', 'layer_3_add_c_out_32_stride_2', 'SharpSepConv32', 'add-SharpSep', 'global_pooling', 'Linear']
+MULTI_CHANNEL_RANDOM_PATH = ['Source', 'Conv3x3_1', 'BatchNorm_1', 'layer_0_stride_1_c_in_64_c_out_128_op_type_ResizablePool', 'layer_0_add_c_out_128_stride_1', 'layer_0_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_0_add_c_out_128_stride_2', 'layer_1_stride_1_c_in_128_c_out_256_op_type_ResizablePool', 'layer_1_add_c_out_256_stride_1', 'layer_1_stride_2_c_in_256_c_out_256_op_type_SharpSepConv', 'layer_1_add_c_out_256_stride_2', 'layer_2_stride_1_c_in_256_c_out_128_op_type_SharpSepConv', 'layer_2_add_c_out_128_stride_1', 'layer_2_stride_2_c_in_128_c_out_32_op_type_SharpSepConv', 'layer_2_add_c_out_32_stride_2', 'layer_3_stride_1_c_in_32_c_out_64_op_type_ResizablePool', 'layer_3_add_c_out_64_stride_1', 'layer_3_stride_2_c_in_64_c_out_32_op_type_SharpSepConv', 'layer_3_add_c_out_32_stride_2', 'SharpSepConv32', 'add-SharpSep', 'global_pooling', 'Linear']
+MULTI_CHANNEL_RANDOM_OPTIMAL = ['Source', 'Conv3x3_1', 'BatchNorm_1', 'layer_0_stride_1_c_in_64_c_out_64_op_type_SharpSepConv', 'layer_0_add_c_out_64_stride_1', 'layer_0_stride_2_c_in_64_c_out_128_op_type_ResizablePool', 'layer_0_add_c_out_128_stride_2', 'layer_1_stride_1_c_in_128_c_out_32_op_type_ResizablePool', 'layer_1_add_c_out_32_stride_1', 'layer_1_stride_2_c_in_32_c_out_256_op_type_SharpSepConv', 'layer_1_add_c_out_256_stride_2', 'layer_2_stride_1_c_in_256_c_out_32_op_type_ResizablePool', 'layer_2_add_c_out_32_stride_1', 'layer_2_stride_2_c_in_32_c_out_256_op_type_ResizablePool', 'layer_2_add_c_out_256_stride_2', 'layer_3_stride_1_c_in_256_c_out_128_op_type_SharpSepConv', 'layer_3_add_c_out_128_stride_1', 'layer_3_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_3_add_c_out_128_stride_2', 'SharpSepConv128', 'add-SharpSep', 'global_pooling', 'Linear']
# costar@ubuntu|~/src/sharpDARTS/cnn on multi_channel_search!?
# ± export CUDA_VISIBLE_DEVICES="0" && python3 train_search.py --dataset cifar10 --batch_size 48 --layers_of_cells 8 --layers_in_cells 4 --save max_w_SharpSepConvDARTS_SEARCH_`git rev-parse --short HEAD` --init_channels
@@ -297,4 +298,4 @@
# [0.0791, 0.4590, 0.0665, 0.0518, 0.0843, 0.0804, 0.0846, 0.0944],
# [0.0715, 0.0665, 0.4912, 0.0401, 0.0822, 0.0816, 0.0888, 0.0780]],
# device='cuda:0', grad_fn=)
-SHARPSEPCONV_DARTS_MAX_W = Genotype(normal=[('dil_conv_3x3', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 2), ('skip_connect', 0), ('avg_pool_3x3', 2), ('sep_conv_3x3', 0), ('avg_pool_3x3', 4), ('max_pool_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('dil_conv_5x5', 2), ('sep_conv_5x5', 0), ('sep_conv_5x5', 0), ('sep_conv_3x3', 2), ('dil_conv_3x3', 0), ('dil_conv_5x5', 3)], reduce_concat=range(2, 6), layout='cell')
\ No newline at end of file
+SHARPSEPCONV_DARTS_MAX_W = Genotype(normal=[('dil_conv_3x3', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 2), ('skip_connect', 0), ('avg_pool_3x3', 2), ('sep_conv_3x3', 0), ('avg_pool_3x3', 4), ('max_pool_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('dil_conv_5x5', 2), ('sep_conv_5x5', 0), ('sep_conv_5x5', 0), ('sep_conv_3x3', 2), ('dil_conv_3x3', 0), ('dil_conv_5x5', 3)], reduce_concat=range(2, 6), layout='cell')
From 6f0190ef60679fea25f63da4804ccdd0ad4c4597 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:27:01 -0400
Subject: [PATCH 08/40] cnn/genotypes.py comments fix
---
cnn/genotypes.py | 47 +++++++++++++++++++++++------------------------
1 file changed, 23 insertions(+), 24 deletions(-)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index 7ee94c5..f6833a7 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -276,31 +276,30 @@
MULTI_CHANNEL_RANDOM_PATH = ['Source', 'Conv3x3_1', 'BatchNorm_1', 'layer_0_stride_1_c_in_64_c_out_128_op_type_ResizablePool', 'layer_0_add_c_out_128_stride_1', 'layer_0_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_0_add_c_out_128_stride_2', 'layer_1_stride_1_c_in_128_c_out_256_op_type_ResizablePool', 'layer_1_add_c_out_256_stride_1', 'layer_1_stride_2_c_in_256_c_out_256_op_type_SharpSepConv', 'layer_1_add_c_out_256_stride_2', 'layer_2_stride_1_c_in_256_c_out_128_op_type_SharpSepConv', 'layer_2_add_c_out_128_stride_1', 'layer_2_stride_2_c_in_128_c_out_32_op_type_SharpSepConv', 'layer_2_add_c_out_32_stride_2', 'layer_3_stride_1_c_in_32_c_out_64_op_type_ResizablePool', 'layer_3_add_c_out_64_stride_1', 'layer_3_stride_2_c_in_64_c_out_32_op_type_SharpSepConv', 'layer_3_add_c_out_32_stride_2', 'SharpSepConv32', 'add-SharpSep', 'global_pooling', 'Linear']
MULTI_CHANNEL_RANDOM_OPTIMAL = ['Source', 'Conv3x3_1', 'BatchNorm_1', 'layer_0_stride_1_c_in_64_c_out_64_op_type_SharpSepConv', 'layer_0_add_c_out_64_stride_1', 'layer_0_stride_2_c_in_64_c_out_128_op_type_ResizablePool', 'layer_0_add_c_out_128_stride_2', 'layer_1_stride_1_c_in_128_c_out_32_op_type_ResizablePool', 'layer_1_add_c_out_32_stride_1', 'layer_1_stride_2_c_in_32_c_out_256_op_type_SharpSepConv', 'layer_1_add_c_out_256_stride_2', 'layer_2_stride_1_c_in_256_c_out_32_op_type_ResizablePool', 'layer_2_add_c_out_32_stride_1', 'layer_2_stride_2_c_in_32_c_out_256_op_type_ResizablePool', 'layer_2_add_c_out_256_stride_2', 'layer_3_stride_1_c_in_256_c_out_128_op_type_SharpSepConv', 'layer_3_add_c_out_128_stride_1', 'layer_3_stride_2_c_in_128_c_out_128_op_type_SharpSepConv', 'layer_3_add_c_out_128_stride_2', 'SharpSepConv128', 'add-SharpSep', 'global_pooling', 'Linear']
-# costar@ubuntu|~/src/sharpDARTS/cnn on multi_channel_search!?
-# ± export CUDA_VISIBLE_DEVICES="0" && python3 train_search.py --dataset cifar10 --batch_size 48 --layers_of_cells 8 --layers_in_cells 4 --save max_w_SharpSepConvDARTS_SEARCH_`git rev-parse --short HEAD` --init_channels
-# 16 --epochs 120 --cutout --autoaugment --seed 22 --weighting_algorithm max_w --primitives DARTS_PRIMITIVES
-# Tensorflow is not installed. Skipping tf related imports
-# Experiment dir : search-20190321-024555-max_w_SharpSepConvDARTS_SEARCH_5e49783-cifar10-DARTS_PRIMITIVES-OPS-0
-# 2019_03_21_19_11_44 epoch, 47, train_acc, 76.215997, valid_acc, 74.855997, train_loss, 0.687799, valid_loss, 0.734363, lr, 1.580315e-02, best_epoch, 47, best_valid_acc, 74.855997
-# 2019_03_21_19_11_44 genotype =
-# 2019_03_21_19_11_44 alphas_normal = tensor([[0.1134, 0.0945, 0.0894, 0.1007, 0.1466, 0.1334, 0.1964, 0.1256],
-# [0.1214, 0.0983, 0.1000, 0.1072, 0.1675, 0.1383, 0.1167, 0.1507],
-# [0.1251, 0.1066, 0.1043, 0.1674, 0.1295, 0.1237, 0.1209, 0.1225],
-# [0.1238, 0.1066, 0.1054, 0.1108, 0.1331, 0.1418, 0.1145, 0.1641],
-# [0.1009, 0.0843, 0.0801, 0.0802, 0.2970, 0.1168, 0.1329, 0.1078],
-# [0.1257, 0.1115, 0.1087, 0.1158, 0.1641, 0.1312, 0.1305, 0.1125],
-# [0.1662, 0.1154, 0.1152, 0.1194, 0.1234, 0.1248, 0.1222, 0.1134],
-# [0.1177, 0.0943, 0.1892, 0.0836, 0.1285, 0.1317, 0.1286, 0.1263],
-# [0.3851, 0.0835, 0.0718, 0.0554, 0.1031, 0.1047, 0.1011, 0.0953],
-# [0.1249, 0.1119, 0.1096, 0.1156, 0.1284, 0.1177, 0.1157, 0.1762],
-# [0.1249, 0.1186, 0.1197, 0.1244, 0.1254, 0.1319, 0.1238, 0.1312],
-# [0.1126, 0.0932, 0.2448, 0.0838, 0.1132, 0.1141, 0.1263, 0.1120],
-# [0.0791, 0.4590, 0.0665, 0.0518, 0.0843, 0.0804, 0.0846, 0.0944],
-# [0.0715, 0.0665, 0.4912, 0.0401, 0.0822, 0.0816, 0.0888, 0.0780]],
-# device='cuda:0', grad_fn=)
-# SHARPSEPCONV_DARTS_MAX_W = Genotype(normal=[('dil_conv_3x3', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 2), ('skip_connect', 0), ('avg_pool_3x3', 2), ('sep_conv_3x3', 0), ('avg_pool_3x3', 4), ('max_pool_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('dil_conv_5x5', 2), ('sep_conv_5x5', 0), ('sep_conv_5x5', 0), ('sep_conv_3x3', 2), ('dil_conv_3x3', 0), ('dil_conv_5x5', 3)], reduce_concat=range(2, 6), layout='cell')
-
'''
+costar@ubuntu|~/src/sharpDARTS/cnn on multi_channel_search!?
+± export CUDA_VISIBLE_DEVICES="0" && python3 train_search.py --dataset cifar10 --batch_size 48 --layers_of_cells 8 --layers_in_cells 4 --save max_w_SharpSepConvDARTS_SEARCH_`git rev-parse --short HEAD` --init_channels
+16 --epochs 120 --cutout --autoaugment --seed 22 --weighting_algorithm max_w --primitives DARTS_PRIMITIVES
+Tensorflow is not installed. Skipping tf related imports
+Experiment dir : search-20190321-024555-max_w_SharpSepConvDARTS_SEARCH_5e49783-cifar10-DARTS_PRIMITIVES-OPS-0
+2019_03_21_19_11_44 epoch, 47, train_acc, 76.215997, valid_acc, 74.855997, train_loss, 0.687799, valid_loss, 0.734363, lr, 1.580315e-02, best_epoch, 47, best_valid_acc, 74.855997
+2019_03_21_19_11_44 genotype =
+2019_03_21_19_11_44 alphas_normal = tensor([[0.1134, 0.0945, 0.0894, 0.1007, 0.1466, 0.1334, 0.1964, 0.1256],
+ [0.1214, 0.0983, 0.1000, 0.1072, 0.1675, 0.1383, 0.1167, 0.1507],
+ [0.1251, 0.1066, 0.1043, 0.1674, 0.1295, 0.1237, 0.1209, 0.1225],
+ [0.1238, 0.1066, 0.1054, 0.1108, 0.1331, 0.1418, 0.1145, 0.1641],
+ [0.1009, 0.0843, 0.0801, 0.0802, 0.2970, 0.1168, 0.1329, 0.1078],
+ [0.1257, 0.1115, 0.1087, 0.1158, 0.1641, 0.1312, 0.1305, 0.1125],
+ [0.1662, 0.1154, 0.1152, 0.1194, 0.1234, 0.1248, 0.1222, 0.1134],
+ [0.1177, 0.0943, 0.1892, 0.0836, 0.1285, 0.1317, 0.1286, 0.1263],
+ [0.3851, 0.0835, 0.0718, 0.0554, 0.1031, 0.1047, 0.1011, 0.0953],
+ [0.1249, 0.1119, 0.1096, 0.1156, 0.1284, 0.1177, 0.1157, 0.1762],
+ [0.1249, 0.1186, 0.1197, 0.1244, 0.1254, 0.1319, 0.1238, 0.1312],
+ [0.1126, 0.0932, 0.2448, 0.0838, 0.1132, 0.1141, 0.1263, 0.1120],
+ [0.0791, 0.4590, 0.0665, 0.0518, 0.0843, 0.0804, 0.0846, 0.0944],
+ [0.0715, 0.0665, 0.4912, 0.0401, 0.0822, 0.0816, 0.0888, 0.0780]],
+ device='cuda:0', grad_fn=)
+SHARPSEPCONV_DARTS_MAX_W = Genotype(normal=[('dil_conv_3x3', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 2), ('skip_connect', 0), ('avg_pool_3x3', 2), ('sep_conv_3x3', 0), ('avg_pool_3x3', 4), ('max_pool_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('dil_conv_5x5', 2), ('sep_conv_5x5', 0), ('sep_conv_5x5', 0), ('sep_conv_3x3', 2), ('dil_conv_3x3', 0), ('dil_conv_5x5', 3)], reduce_concat=range(2, 6), layout='cell')
2019_03_22_20_40_54 alphas_normal = tensor([[0.0232, 0.0151, 0.0171, 0.0194, 0.0332, 0.0312, 0.8298, 0.0309],
[0.0286, 0.0168, 0.0197, 0.0224, 0.0504, 0.0883, 0.0418, 0.7321],
[0.0877, 0.0575, 0.0670, 0.3865, 0.0951, 0.0988, 0.1257, 0.0818],
From 0c41d9415cc4be4f98b73baf3484e20e59f0c413 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:35:18 -0400
Subject: [PATCH 09/40] cnn/genotypes.py sharper add missing ops
---
cnn/genotypes.py | 1 +
cnn/operations.py | 2 ++
2 files changed, 3 insertions(+)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index a3de208..3c05056 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -37,6 +37,7 @@
'flood_conv_3x3',
'flood_conv_5x5',
'dil_flood_conv_3x3',
+ 'dil_flood_conv_5x5',
# 'choke_conv_3x3',
# 'dil_choke_conv_3x3',
]
diff --git a/cnn/operations.py b/cnn/operations.py
index d02cc52..502a7e8 100644
--- a/cnn/operations.py
+++ b/cnn/operations.py
@@ -9,6 +9,7 @@
'skip_connect': lambda C_in, C_out, stride, affine, C_mid=None: Identity() if stride == 1 else FactorizedReduce(C_in, C_out, 1, stride, 0, affine=affine),
'sep_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 3, stride, padding=1, affine=affine),
'sep_conv_5x5': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 5, stride, padding=2, affine=affine),
+ 'flood_conv_5x5': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 5, stride, padding=2, affine=affine, C_mid_mult=4),
'sep_conv_7x7': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 7, stride, padding=3, affine=affine),
'dil_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 3, stride, padding=2, dilation=2, affine=affine),
'dil_conv_5x5': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 5, stride, padding=4, dilation=2, affine=affine),
@@ -20,6 +21,7 @@
),
'flood_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 3, stride, padding=1, affine=affine, C_mid_mult=4),
'dil_flood_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 3, stride, padding=2, dilation=2, affine=affine, C_mid_mult=4),
+ 'dil_flood_conv_5x5': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 5, stride, padding=2, dilation=2, affine=affine, C_mid_mult=4),
'choke_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=32: SharpSepConv(C_in, C_out, 3, stride, padding=1, affine=affine, C_mid=C_mid),
'dil_choke_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=32: SharpSepConv(C_in, C_out, 3, stride, padding=2, dilation=2, affine=affine, C_mid=C_mid),
}
From 6b5c16194563fd9a1ac0df53ae3f38fd03bf5958 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:47:24 -0400
Subject: [PATCH 10/40] cnn/operations.py sharper flood_conv_3x3 added
---
cnn/operations.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/cnn/operations.py b/cnn/operations.py
index 502a7e8..992a72f 100644
--- a/cnn/operations.py
+++ b/cnn/operations.py
@@ -9,6 +9,7 @@
'skip_connect': lambda C_in, C_out, stride, affine, C_mid=None: Identity() if stride == 1 else FactorizedReduce(C_in, C_out, 1, stride, 0, affine=affine),
'sep_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 3, stride, padding=1, affine=affine),
'sep_conv_5x5': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 5, stride, padding=2, affine=affine),
+ 'flood_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 3, stride, padding=2, affine=affine, C_mid_mult=4),
'flood_conv_5x5': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 5, stride, padding=2, affine=affine, C_mid_mult=4),
'sep_conv_7x7': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 7, stride, padding=3, affine=affine),
'dil_conv_3x3': lambda C_in, C_out, stride, affine, C_mid=None: SharpSepConv(C_in, C_out, 3, stride, padding=2, dilation=2, affine=affine),
From 9342d1e7a53c1ef9db24fe654dd5214168ae2f9a Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:56:19 -0400
Subject: [PATCH 11/40] cnn/genotypes.py SHARPER_PRIMITIVES disable
dil_flood_conv_5x5 due to bug
---
cnn/genotypes.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index 3c05056..d9f7648 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -37,7 +37,10 @@
'flood_conv_3x3',
'flood_conv_5x5',
'dil_flood_conv_3x3',
- 'dil_flood_conv_5x5',
+ # TODO(ahundt) sharpsepconv doesn't correctly support dil_flood_conv_5x5, padding is not sufficient
+ # w shape: torch.Size([]) op type: i: 12 self._primitives[i]: dil_flood_conv_5x5x size: torch.Size([16, 16, 32, 32]) stride: 1
+ # op_out size: torch.Size([16, 16, 28, 28])
+ # 'dil_flood_conv_5x5',
# 'choke_conv_3x3',
# 'dil_choke_conv_3x3',
]
From efa1168b2e8d81bd56c5016d139d86ecb3ae96c9 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Tue, 9 Apr 2019 17:59:29 -0400
Subject: [PATCH 12/40] cnn/model_search.py fix debugging code for MixedOp()
class
---
cnn/model_search.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/cnn/model_search.py b/cnn/model_search.py
index d695814..dd63d9d 100644
--- a/cnn/model_search.py
+++ b/cnn/model_search.py
@@ -29,6 +29,7 @@ def __init__(self, C, stride, primitives=None, op_dict=None, weighting_algorithm
self._stride = stride
if primitives is None:
primitives = PRIMITIVES
+ self._primitives = primitives
if op_dict is None:
op_dict = operations.OPS
for primitive in primitives:
@@ -44,7 +45,7 @@ def forward(self, x, weights):
# print('-------------------- forward')
# print('weights shape: ' + str(len(weights)) + ' ops shape: ' + str(len(self._ops)))
# for i, (w, op) in enumerate(zip(weights, self._ops)):
- # print('w shape: ' + str(w.shape) + ' op type: ' + str(type(op)) + ' i: ' + str(i) + ' PRIMITIVES[i]: ' + str(PRIMITIVES[i]) + 'x size: ' + str(x.size()) + ' stride: ' + str(self._stride))
+ # print('w shape: ' + str(w.shape) + ' op type: ' + str(type(op)) + ' i: ' + str(i) + ' self._primitives[i]: ' + str(self._primitives[i]) + 'x size: ' + str(x.size()) + ' stride: ' + str(self._stride))
# op_out = op(x)
# print('op_out size: ' + str(op_out.size()))
# result += w * op_out
From 17fbc78751fbdba8f381b3fbfdf9d90e7f556e2d Mon Sep 17 00:00:00 2001
From: Priyanka Hubli
Date: Fri, 19 Apr 2019 20:25:35 -0400
Subject: [PATCH 13/40] modified TDCFeaturizer forward function to be able to
choose different outputs
---
cnn/model.py | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/cnn/model.py b/cnn/model.py
index 413c4d5..4b7c796 100644
--- a/cnn/model.py
+++ b/cnn/model.py
@@ -575,7 +575,9 @@ class TDCFeaturizer(nn.Module):
For the classifier, we do a multiplication between both feature vectors
followed by a fully connected layer.
-
+ Set 'classify_frame_distance' as True if we want the predicted class from the model.
+ To just get the embeddings, set 'classify_frame_distance' as False and 'frame_embeddings'
+ as True.
"""
def __init__(self):
super(TDCFeaturizer, self).__init__()
@@ -593,7 +595,12 @@ def __init__(self):
self.fc2 = nn.Linear(self.feature_vector_size, self.feature_vector_size)
self.fc3 = nn.Linear(1024, self.feature_vector_size)
self.fc4 = nn.Linear(self.feature_vector_size, 6) # size of each label
+ self.classify_frame_distance = True
+ self.frame_embeddings = False
+ def choose_outputs(self, classify_frame_distance = True, frame_embeddings = False):
+ self.classify_frame_distance = classify_frame_distance
+ self.frame_embeddings = frame_embeddings
def forward(self, img_1, img_2):
logits_aux = None
@@ -609,9 +616,9 @@ def forward(self, img_1, img_2):
x = F.relu(self.fc1(x))
feature_vector = self.fc2(x)
- feature_vector = F.normalize(feature_vector, p=2, dim=1)
- #if not self.training:
- # return feature_vector
+ feature_vector = F.normalize(feature_vector, p=2, dim=1)
+ if self.frame_embeddings and not self.classify_frame_distance:
+ return feature_vector
feature_vector_stack = feature_vector.view(-1, 2, self.feature_vector_size)
combined_embeddings = torch.mul(feature_vector_stack[:, 0, :], feature_vector_stack[:, 1, :])
@@ -619,5 +626,8 @@ def forward(self, img_1, img_2):
x = F.relu(self.fc3(combined_embeddings))
prediction = F.relu(self.fc4(x))
- return prediction, logits_aux
+ if self.classify_frame_distance and not self.frame_embeddings:
+ return prediction , logits_aux
+ if self.classify_frame_distance and self.frame_embeddings:
+ return (prediction, feature_vector, logits_aux)
From 7e1636259f52812ffc2625b5a556fea910e92013 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Sat, 20 Apr 2019 12:49:45 -0400
Subject: [PATCH 14/40] cnn/genotypes.py add first "sharper" search space
models
---
cnn/genotypes.py | 90 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 89 insertions(+), 1 deletion(-)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index d9f7648..b29b59a 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -389,7 +389,6 @@
2019_03_26_22_47_45 genotype = Genotype(normal=[('sep_conv_3x3', 0), ('choke_conv_3x3', 1), ('skip_connect', 0), ('dil_conv_3x3', 2), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 0), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('dil_choke_conv_3x3', 0), ('dil_flood_conv_3x3', 2), ('dil_conv_3x3', 0), ('skip_connect', 3), ('flood_conv_3x3', 0), ('skip_connect', 3)], reduce_concat=range(2, 6), layout='cell')
2019_03_26_22_47_45 alphas_normal = tensor([[0.0143, 0.0093, 0.0108, 0.8871, 0.0147, 0.0156, 0.0162, 0.0170, 0.0150],
-
[0.0372, 0.0194, 0.0285, 0.0438, 0.0300, 0.0522, 0.0522, 0.6729, 0.0637],
[0.0251, 0.0151, 0.8027, 0.0271, 0.0251, 0.0254, 0.0278, 0.0270, 0.0247],
[0.0345, 0.0207, 0.0290, 0.0423, 0.0373, 0.7211, 0.0346, 0.0405, 0.0400],
@@ -437,3 +436,92 @@
Experiment dir : eval-20190327-141933-SHARP_DARTS_MAX_W_2k_c1059c7_cospower_min_1e-8-cifar10-SHARP_DARTS_MAX_W-0
"""
SHARP_DARTS_MAX_W = Genotype(normal=[('sep_conv_3x3', 0), ('choke_conv_3x3', 1), ('skip_connect', 0), ('dil_conv_3x3', 2), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 0), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('dil_choke_conv_3x3', 0), ('dil_flood_conv_3x3', 2), ('dil_conv_3x3', 0), ('skip_connect', 3), ('flood_conv_3x3', 0), ('skip_connect', 3)], reduce_concat=range(2, 6), layout='cell')
+
+"""
+ahundt@femur|~/src/darts/cnn on sharper?
+± export CUDA_VISIBLE_DEVICES="2" && python3 train_search.py --dataset cifar10 --batch_size 16 --layers_of_cells 8 --layers_in_cells 4 --save SHARPER_SEARCH_`git rev-parse --short HEAD` --init_channels 16 --epochs 120 --cutout --autoaugment --seed 22 --primitives SHARPER_PRIMITIVES
+2019_04_09_18_33_45 gpu device = 0
+2019_04_09_18_33_45 args = Namespace(arch='SHARPER_PRIMITIVES-OPS', arch_learning_rate=0.0003, arch_weight_decay=0.001, autoaugment=True, batch_size=16, cutout=True, cutout_length=16, data='../data', dataset='cifar10', drop_path_prob=0.3, epoch_stats_file='search-20190409-183345-SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0/eval-epoch-stats-20190409-183345.json', epochs=120, evaluate='', final_path=None, gpu=0, grad_clip=5, init_channels=16, layers_in_cells=4, layers_of_cells=8, learning_rate=0.025, learning_rate_min=0.0001, load='', load_args='', load_genotype=None, log_file_path='search-20190409-183345-SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0/log.txt', lr_power_annealing_exponent_order=2, mid_channels=32, model_path='saved_models', momentum=0.9, multi_channel=False, no_architect=False, ops='OPS', primitives='SHARPER_PRIMITIVES', random_eraser=False, report_freq=50, save='search-20190409-183345-SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0', seed=22, start_epoch=1, stats_file='search-20190409-183345-SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0/eval-stats-20190409-183345.json', train_portion=0.5, unrolled=False, warmup_epochs=5, weight_decay=0.0003, weighting_algorithm='scalar')
+2019_04_09_18_33_45 loading op dict: operations.OPS
+2019_04_09_18_33_45 loading primitives:genotypes.SHARPER_PRIMITIVES
+2019_04_09_18_33_45 primitives: ['none', 'max_pool_3x3', 'avg_pool_3x3', 'skip_connect', 'sep_conv_3x3', 'sep_conv_5x5', 'sep_conv_7x7', 'dil_conv_3x3', 'dil_conv_5x5', 'flood_conv_3x3', 'flood_conv_5x5', 'dil_flood_conv_3x3']
+2019_04_09_18_33_49 param size = 9.707002MB
+2019_04_19_14_33_25 alphas_normal = tensor([[0.1108, 0.0556, 0.0575, 0.2509, 0.1022, 0.0461, 0.0347, 0.0274, 0.0378, 0.2145, 0.0266, 0.0359],
+ [0.3534, 0.0249, 0.0230, 0.0314, 0.1636, 0.0603, 0.0392, 0.0490, 0.0627, 0.1044, 0.0464, 0.0417],
+ [0.5115, 0.0438, 0.0384, 0.0831, 0.0495, 0.0549, 0.0467, 0.0462, 0.0292, 0.0390, 0.0229, 0.0348],
+ [0.6162, 0.0238, 0.0217, 0.0320, 0.0882, 0.0679, 0.0205, 0.0213, 0.0237, 0.0291, 0.0289, 0.0267],
+ [0.7525, 0.0170, 0.0157, 0.0279, 0.0271, 0.0264, 0.0367, 0.0240, 0.0161, 0.0198, 0.0203, 0.0165],
+ [0.3173, 0.0881, 0.0614, 0.1120, 0.0474, 0.0473, 0.0461, 0.0410, 0.0378, 0.0895, 0.0414, 0.0707],
+ [0.3855, 0.0335, 0.0304, 0.0456, 0.0678, 0.0496, 0.0579, 0.0441, 0.0467, 0.1161, 0.0841, 0.0389],
+ [0.5562, 0.0272, 0.0226, 0.0429, 0.0706, 0.0511, 0.0392, 0.0321, 0.0275, 0.0596, 0.0366, 0.0344],
+ [0.1158, 0.0256, 0.0253, 0.0423, 0.1826, 0.0349, 0.0435, 0.0868, 0.0274, 0.0752, 0.1449, 0.1957],
+ [0.2988, 0.0673, 0.0460, 0.0676, 0.0678, 0.0567, 0.0483, 0.0704, 0.0604, 0.1230, 0.0485, 0.0452],
+ [0.3221, 0.0363, 0.0330, 0.0455, 0.0809, 0.0457, 0.0519, 0.0636, 0.0689, 0.1469, 0.0629, 0.0421],
+ [0.4835, 0.0269, 0.0227, 0.0398, 0.0528, 0.0671, 0.0407, 0.0762, 0.0554, 0.0495, 0.0554, 0.0300],
+ [0.0593, 0.0200, 0.0193, 0.0318, 0.0606, 0.0445, 0.0292, 0.0412, 0.0520, 0.1620, 0.0341, 0.4460],
+ [0.0821, 0.0228, 0.0230, 0.0340, 0.1011, 0.0903, 0.0396, 0.1702, 0.0370, 0.1469, 0.0921, 0.1609]], device='cuda:0', grad_fn=)
+2019_04_19_14_33_25 alphas_reduce = tensor([[0.0628, 0.2237, 0.1198, 0.0752, 0.0712, 0.0598, 0.0775, 0.0537, 0.0651, 0.0707, 0.0613, 0.0594],
+ [0.0812, 0.1069, 0.1021, 0.1551, 0.0841, 0.0636, 0.0473, 0.0726, 0.0584, 0.0799, 0.0786, 0.0701],
+ [0.0625, 0.1197, 0.1379, 0.0985, 0.1186, 0.0799, 0.0425, 0.0679, 0.0458, 0.0692, 0.0832, 0.0743],
+ [0.0708, 0.0994, 0.1058, 0.1389, 0.0632, 0.0556, 0.0569, 0.0937, 0.0654, 0.1025, 0.0836, 0.0641],
+ [0.0874, 0.0765, 0.0767, 0.1159, 0.0823, 0.1001, 0.0772, 0.0783, 0.0534, 0.1009, 0.0804, 0.0708],
+ [0.0731, 0.0977, 0.1059, 0.1180, 0.0564, 0.1049, 0.0580, 0.0632, 0.0664, 0.0704, 0.0640, 0.1219],
+ [0.0816, 0.1009, 0.1261, 0.0929, 0.0817, 0.0604, 0.0824, 0.0925, 0.0606, 0.0622, 0.0848, 0.0740],
+ [0.0923, 0.0670, 0.0673, 0.0952, 0.1105, 0.0709, 0.0742, 0.0857, 0.1044, 0.0679, 0.0793, 0.0852],
+ [0.0977, 0.0673, 0.0777, 0.1163, 0.0792, 0.0727, 0.0850, 0.0836, 0.1078, 0.0856, 0.0502, 0.0769],
+ [0.0722, 0.1031, 0.1275, 0.0822, 0.0937, 0.0941, 0.0848, 0.0808, 0.0673, 0.0681, 0.0698, 0.0565],
+ [0.0762, 0.1123, 0.1090, 0.0942, 0.0699, 0.0770, 0.0775, 0.0765, 0.0812, 0.0897, 0.0716, 0.0650],
+ [0.0903, 0.0703, 0.0717, 0.1145, 0.0846, 0.0823, 0.0826, 0.0938, 0.0651, 0.0900, 0.0846, 0.0701],
+ [0.0935, 0.0614, 0.0651, 0.1099, 0.1085, 0.0799, 0.0833, 0.0786, 0.0622, 0.1417, 0.0515, 0.0644],
+ [0.1492, 0.0676, 0.0754, 0.1314, 0.0717, 0.1051, 0.0829, 0.0670, 0.0863, 0.0683, 0.0518, 0.0432]], device='cuda:0', grad_fn=)
+Overview ***** best_epoch: 113 best_valid_acc: 86.48 ***** Progress: 99%|| 119/120 [235:59:34<1:59:19, 7159.36s/itTraceback (most recent call last):91.89, top 5: 98.82 progress: 5%|| 74/1563 [05:08<1:43:31, 4.17s/it]
+2019_04_19_16_32_32 epoch, 120, train_acc, 91.084000, valid_acc, 86.732000, train_loss, 0.260623, valid_loss, 0.394877, lr, 1.000000e-04, best_epoch, 120, best_valid_acc, 86.732000
+Overview ***** best_epoch: 120 best_valid_acc: 86.73 ***** Progress: 100%|| 120/120 [237:58:43<00:00, 7156.24s/it]
+2019_04_19_16_32_34 genotype = Genotype(normal=[('skip_connect', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), ('skip_connect', 0), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 1), ('dil_flood_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3), ('skip_connect', 4)], reduce_concat=range(2, 6), layout='cell')
+2019_04_19_16_32_34 Search for Model Complete! Save dir: search-20190409-183345-SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0
+"""
+
+SHARPER_SCALAR = Genotype(normal=[('skip_connect', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), ('skip_connect', 0), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 1), ('dil_flood_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3), ('skip_connect', 4)], reduce_concat=range(2, 6), layout='cell')
+
+"""
+
+ahundt@femur|~/src/darts/cnn on sharper?
+± export CUDA_VISIBLE_DEVICES="0" && python3 train_search.py --dataset cifar10 --batch_size 16 --layers_of_cells 8 --layers_in_cells 4 --save max_w_SHARPER_SEARCH_`git rev-parse --short HEAD` --init_channels 16 --epochs 120 --cutout --autoaugment --seed 22 --weighting_algorithm max_w --primitives SHARPER_PRIMITIVES
+2019_04_19_20_07_23 epoch, 119, train_acc, 88.696000, valid_acc, 84.868000, train_loss, 0.327119, valid_loss, 0.456210, lr, 1.032201e-04, best_epoch, 119, best_valid_acc, 84.868000
+2019_04_19_20_07_25 genotype = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
+2019_04_19_20_07_25 alphas_normal = tensor([[0.0064, 0.0045, 0.0048, 0.0053, 0.9306, 0.0070, 0.0069, 0.0070, 0.0064, 0.0066, 0.0069, 0.0076],
+ [0.0527, 0.0296, 0.0307, 0.0398, 0.0742, 0.0773, 0.0469, 0.1153, 0.2443, 0.1075, 0.0677, 0.1140],
+ [0.0392, 0.5563, 0.0226, 0.0266, 0.0424, 0.0451, 0.0452, 0.0414, 0.0485, 0.0419, 0.0433, 0.0476],
+ [0.0692, 0.0517, 0.0510, 0.0607, 0.0794, 0.2549, 0.0680, 0.0732, 0.0677, 0.0699, 0.0744, 0.0799],
+ [0.0454, 0.0421, 0.0343, 0.0414, 0.0426, 0.0447, 0.5136, 0.0453, 0.0458, 0.0522, 0.0464, 0.0460],
+ [0.0111, 0.0090, 0.0093, 0.0099, 0.0111, 0.0114, 0.0113, 0.0108, 0.0111, 0.8829, 0.0108, 0.0113],
+ [0.0610, 0.0434, 0.0440, 0.0507, 0.0652, 0.0654, 0.0673, 0.0664, 0.0790, 0.0715, 0.3231, 0.0629],
+ [0.0512, 0.0389, 0.0340, 0.4399, 0.0558, 0.0542, 0.0536, 0.0563, 0.0582, 0.0515, 0.0535, 0.0529],
+ [0.0081, 0.0071, 0.9128, 0.0058, 0.0081, 0.0083, 0.0082, 0.0083, 0.0082, 0.0085, 0.0083, 0.0082],
+ [0.0772, 0.0519, 0.0568, 0.0651, 0.0911, 0.1073, 0.1002, 0.1074, 0.0702, 0.0717, 0.0935, 0.1075],
+ [0.0779, 0.0605, 0.0629, 0.0704, 0.0858, 0.0788, 0.0745, 0.0790, 0.0771, 0.1685, 0.0820, 0.0824],
+ [0.0795, 0.0674, 0.0584, 0.1416, 0.0774, 0.0742, 0.0791, 0.0843, 0.0848, 0.0799, 0.0824, 0.0909],
+ [0.5488, 0.0359, 0.0321, 0.0295, 0.0464, 0.0443, 0.0413, 0.0444, 0.0459, 0.0438, 0.0430, 0.0445],
+ [0.6040, 0.0317, 0.0297, 0.0233, 0.0423, 0.0379, 0.0389, 0.0354, 0.0369, 0.0379, 0.0445, 0.0376]], device='cuda:0', grad_fn=)
+2019_04_19_20_07_25 alphas_reduce = tensor([[0.0370, 0.0326, 0.0338, 0.0345, 0.0368, 0.0377, 0.0339, 0.0378, 0.0322, 0.0370, 0.6131, 0.0336],
+ [0.0800, 0.0891, 0.0890, 0.0891, 0.0888, 0.0890, 0.0672, 0.0886, 0.0890, 0.0880, 0.0530, 0.0892],
+ [0.0461, 0.0431, 0.0443, 0.0448, 0.5159, 0.0455, 0.0426, 0.0427, 0.0423, 0.0434, 0.0458, 0.0435],
+ [0.0825, 0.0883, 0.0882, 0.0886, 0.0820, 0.0883, 0.0698, 0.0882, 0.0715, 0.0776, 0.0869, 0.0882],
+ [0.0795, 0.0849, 0.0849, 0.1471, 0.0828, 0.0768, 0.0816, 0.0687, 0.0692, 0.0897, 0.0749, 0.0598],
+ [0.0694, 0.0658, 0.0676, 0.0679, 0.2674, 0.0675, 0.0653, 0.0684, 0.0669, 0.0629, 0.0648, 0.0661],
+ [0.0831, 0.0887, 0.0884, 0.0885, 0.0827, 0.0841, 0.0801, 0.0793, 0.0780, 0.0852, 0.0821, 0.0799],
+ [0.0795, 0.0818, 0.0828, 0.1563, 0.0836, 0.0785, 0.0753, 0.0717, 0.0760, 0.0711, 0.0712, 0.0721],
+ [0.0812, 0.0808, 0.0787, 0.1316, 0.0800, 0.0816, 0.0862, 0.0779, 0.0833, 0.0724, 0.0753, 0.0709],
+ [0.0801, 0.0770, 0.0786, 0.0791, 0.1442, 0.0784, 0.0740, 0.0758, 0.0773, 0.0812, 0.0776, 0.0767],
+ [0.0832, 0.0874, 0.0869, 0.0881, 0.0839, 0.0808, 0.0828, 0.0830, 0.0818, 0.0830, 0.0753, 0.0838],
+ [0.0823, 0.0844, 0.0854, 0.1030, 0.0826, 0.0882, 0.0793, 0.0819, 0.0845, 0.0774, 0.0792, 0.0719],
+ [0.0827, 0.0825, 0.0813, 0.1029, 0.0854, 0.0818, 0.0835, 0.0824, 0.0828, 0.0799, 0.0774, 0.0774],
+ [0.0799, 0.0759, 0.0747, 0.0774, 0.0808, 0.0749, 0.0827, 0.0802, 0.1554, 0.0747, 0.0713, 0.0722]], device='cuda:0', grad_fn=)
+2019_04_19_22_09_50 epoch, 120, train_acc, 89.072000, valid_acc, 84.676000, train_loss, 0.310882, valid_loss, 0.459557, lr, 1.000000e-04, best_epoch, 119, best_valid_acc, 84.868000
+Overview ***** best_epoch: 119 best_valid_acc: 84.87 ***** Progress: 100%|| 120/120 [244:05:44<00:00, 7367.80s/it]
+2019_04_19_22_09_52 genotype = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('max_pool_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5
+x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
+2019_04_19_22_09_52 Search for Model Complete! Save dir: search-20190409-180403-max_w_SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0
+"""
+
+SHARPER_MAX_W = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
From ddc4ff3a6501b4ffa99fb1012136fabc8ac05479 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Sat, 20 Apr 2019 13:00:19 -0400
Subject: [PATCH 15/40] cnn/genotypes.py sharper flops
---
cnn/genotypes.py | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index b29b59a..ab1c4f7 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -479,6 +479,10 @@
Overview ***** best_epoch: 120 best_valid_acc: 86.73 ***** Progress: 100%|| 120/120 [237:58:43<00:00, 7156.24s/it]
2019_04_19_16_32_34 genotype = Genotype(normal=[('skip_connect', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), ('skip_connect', 0), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 1), ('dil_flood_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3), ('skip_connect', 4)], reduce_concat=range(2, 6), layout='cell')
2019_04_19_16_32_34 Search for Model Complete! Save dir: search-20190409-183345-SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0
+
+2019_04_20_12_52_14 param size = 7.109470MB
+2019_04_20_12_52_14 flops_shape = [1, 3, 32, 32]
+2019_04_20_12_52_14 flops = 1.1GMac
"""
SHARPER_SCALAR = Genotype(normal=[('skip_connect', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), ('skip_connect', 0), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 1), ('dil_flood_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3), ('skip_connect', 4)], reduce_concat=range(2, 6), layout='cell')
@@ -487,6 +491,12 @@
ahundt@femur|~/src/darts/cnn on sharper?
± export CUDA_VISIBLE_DEVICES="0" && python3 train_search.py --dataset cifar10 --batch_size 16 --layers_of_cells 8 --layers_in_cells 4 --save max_w_SHARPER_SEARCH_`git rev-parse --short HEAD` --init_channels 16 --epochs 120 --cutout --autoaugment --seed 22 --weighting_algorithm max_w --primitives SHARPER_PRIMITIVES
+2019_04_09_18_04_03 gpu device = 0
+2019_04_09_18_04_03 args = Namespace(arch='SHARPER_PRIMITIVES-OPS', arch_learning_rate=0.0003, arch_weight_decay=0.001, autoaugment=True, batch_size=16, cutout=True, cutout_length=16, data='../data', dataset='cifar10', drop_path_prob=0.3, epoch_stats_file='search-20190409-180403-max_w_SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0/eval-epoch-stats-20190409-180403.json', epochs=120, evaluate='', final_path=None, gpu=0, grad_clip=5, init_channels=16, layers_in_cells=4, layers_of_cells=8, learning_rate=0.025, learning_rate_min=0.0001, load='', load_args='', load_genotype=None, log_file_path='search-20190409-180403-max_w_SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0/log.txt', lr_power_annealing_exponent_order=2, mid_channels=32, model_path='saved_models', momentum=0.9, multi_channel=False, no_architect=False, ops='OPS', primitives='SHARPER_PRIMITIVES', random_eraser=False, report_freq=50, save='search-20190409-180403-max_w_SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0', seed=22, start_epoch=1, stats_file='search-20190409-180403-max_w_SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0/eval-stats-20190409-180403.json', train_portion=0.5, unrolled=False, warmup_epochs=5, weight_decay=0.0003, weighting_algorithm='max_w')
+2019_04_09_18_04_03 loading op dict: operations.OPS
+2019_04_09_18_04_03 loading primitives:genotypes.SHARPER_PRIMITIVES
+2019_04_09_18_04_03 primitives: ['none', 'max_pool_3x3', 'avg_pool_3x3', 'skip_connect', 'sep_conv_3x3', 'sep_conv_5x5', 'sep_conv_7x7', 'dil_conv_3x3', 'dil_conv_5x5', 'flood_conv_3x3', 'flood_conv_5x5', 'dil_flood_conv_3x3']
+2019_04_09_18_04_07 param size = 9.707002MB
2019_04_19_20_07_23 epoch, 119, train_acc, 88.696000, valid_acc, 84.868000, train_loss, 0.327119, valid_loss, 0.456210, lr, 1.032201e-04, best_epoch, 119, best_valid_acc, 84.868000
2019_04_19_20_07_25 genotype = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
2019_04_19_20_07_25 alphas_normal = tensor([[0.0064, 0.0045, 0.0048, 0.0053, 0.9306, 0.0070, 0.0069, 0.0070, 0.0064, 0.0066, 0.0069, 0.0076],
@@ -522,6 +532,10 @@
2019_04_19_22_09_52 genotype = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('max_pool_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5
x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
2019_04_19_22_09_52 Search for Model Complete! Save dir: search-20190409-180403-max_w_SHARPER_SEARCH_efa1168-cifar10-SHARPER_PRIMITIVES-OPS-0
+
+2019_04_20_12_51_18 param size = 6.087142MB
+2019_04_20_12_51_18 flops_shape = [1, 3, 32, 32]
+2019_04_20_12_51_18 flops = 950.22MMac
"""
SHARPER_MAX_W = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
From 8166e1c2d4f6ca63eadc75e756fc2bf19501dea8 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Sat, 20 Apr 2019 13:15:28 -0400
Subject: [PATCH 16/40] cnn/genotypes.py add cifar10 startup command to sharper
models
---
cnn/genotypes.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index ab1c4f7..0e7025b 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -483,6 +483,8 @@
2019_04_20_12_52_14 param size = 7.109470MB
2019_04_20_12_52_14 flops_shape = [1, 3, 32, 32]
2019_04_20_12_52_14 flops = 1.1GMac
+
+for i in {1..8}; do export CUDA_VISIBLE_DEVICES="0" && python3 train.py --b 48 --save SHARPER_SCALAR_2k_`git rev-parse --short HEAD` --arch SHARPER_SCALAR --epochs 2000 --cutout --autoaugment --auxiliary ; done;
"""
SHARPER_SCALAR = Genotype(normal=[('skip_connect', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), ('skip_connect', 0), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 1), ('dil_flood_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3), ('skip_connect', 4)], reduce_concat=range(2, 6), layout='cell')
@@ -536,6 +538,8 @@
2019_04_20_12_51_18 param size = 6.087142MB
2019_04_20_12_51_18 flops_shape = [1, 3, 32, 32]
2019_04_20_12_51_18 flops = 950.22MMac
+
+for i in {1..8}; do export CUDA_VISIBLE_DEVICES="2" && python3 train.py --b 64 --save SHARPER_MAX_W_2k_`git rev-parse --short HEAD` --arch SHARPER_MAX_W --epochs 2000 --cutout --autoaugment --auxiliary ; done;
"""
SHARPER_MAX_W = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
From c4891da52248c982e2082aa81f872fe9ff8c291f Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Sun, 12 May 2019 12:35:26 -0400
Subject: [PATCH 17/40] cnn/genotype_extractor.py added, can disable 'none'
layer hack from DARTS. Also added hacked and unhacked versions of sharper
search space.
---
cnn/genotype_extractor.py | 137 ++++++++++++++++++++++++++++++++++++++
cnn/genotypes.py | 62 +++++++++++++++++
cnn/model_search.py | 67 +++++--------------
3 files changed, 216 insertions(+), 50 deletions(-)
create mode 100644 cnn/genotype_extractor.py
diff --git a/cnn/genotype_extractor.py b/cnn/genotype_extractor.py
new file mode 100644
index 0000000..eaa5b7e
--- /dev/null
+++ b/cnn/genotype_extractor.py
@@ -0,0 +1,137 @@
+'''
+This file includes code from the DARTS and sharpDARTS https://arxiv.org/abs/1903.09900 papers.
+'''
+
+import numpy as np
+import genotypes
+
+
+def parse_cell(weights, primitives, steps=4, skip_primitive='none'):
+ """ Take a weight array and turn it into a list of pairs (primitive_string, node_index).
+ """
+ gene = []
+ n = 2
+ start = 0
+ for add_node_index in range(steps):
+ # Each step is a separate "add node" in the graph, so i is the integer index of the current node.
+ # A better name for i might be add_node_index.
+ end = start + n
+ # Only look at the weights relevant to this node.
+ # "Nodes" 0 and 1 will always be the output of the previous cells.
+ #
+ # All other nodes will be add nodes which need edges connecting back to the previous nodes:
+ # add node 0 will need 2: rows 0, 1
+ # add node 1 will need 3: rows 2, 3, 4
+ # add node 2 will need 4: rows 5, 6, 7, 8
+ # add node 3 will need 5: rows 9, 10, 11, 12, 13
+ # ...and so on if there are more than 4 nodes.
+ W = weights[start:end].copy()
+ # print('add_node_index: ' + str(add_node_index) + ' start: ' + str(start) + ' end: ' + str(end) + ' W shape: ' + str(W.shape))
+ # Each row in the weights is a separate edge, and each column are the possible primitives that edge might use.
+ # The first "add node" can connect back to the two previous cells, which is why the edges are i + 2.
+ # The sorted function orders lists from lowest to highest, so we use -max in the lambda function to sort from highest to lowest.
+ # We currently say there will only be two edges connecting to each node, which is why there is [:2], to select the two highest score edges.
+ # Each later nodes can connect back to the previous cells or an internal node, so the range(i+2) of possible connections increases.
+ pre_edges = sorted(range(add_node_index + 2),
+ key=lambda x: -max(W[x][k] for k in range(len(W[x])) if skip_primitive is None or k != primitives.index(skip_primitive)))
+ edges = pre_edges[:2]
+ # print('edges: ' + str(edges))
+ # We've now selected the two edges we will use for this node, so next let's select the layer primitives.
+ # Each edge needs a particular primitive, so go through all the edges and compare all the possible primitives.
+ for j in edges:
+ k_best = None
+ # note: This probably could be simpler via argmax...
+ # Loop through all the columns to find the highest score primitive for the chosen edge, excluding none.
+ for k in range(len(W[j])):
+ if skip_primitive is None or k != primitives.index(skip_primitive):
+ if k_best is None or W[j][k] > W[j][k_best]:
+ k_best = k
+ # Once the best primitive is chosen, create the new gene element, which is the
+ # string for the name of the primitive, and the index of the previous node to connect to,
+ gene.append((primitives[k_best], j))
+ start = end
+ n += 1
+ # Return the full list of (node, primitive) pairs for this set of weights.
+ return gene
+
+def genotype_cell(alphas_normal, alphas_reduce, primitives, steps=4, multiplier=4, skip_primitive='none'):
+ # skip_primitive = 'none' is a hack in original DARTS, which removes a no-op primitive.
+ # skip_primitive = None means no hack is applied
+ # note the printed weights from a call to Network::arch_weights() in model_search.py
+ # are already post-softmax, so we don't need to apply softmax again
+ # alphas_normal = torch.FloatTensor(genotypes.SHARPER_SCALAR_WEIGHTS.normal)
+ # alphas_reduce = torch.FloatTensor(genotypes.SHARPER_SCALAR_WEIGHTS.reduce)
+ # F.softmax(alphas_normal, dim=-1).data.cpu().numpy()
+ # F.softmax(alphas_reduce, dim=-1).data.cpu().numpy()
+ gene_normal = parse_cell(alphas_normal, primitives, steps, skip_primitive=skip_primitive)
+ gene_reduce = parse_cell(alphas_reduce, primitives, steps, skip_primitive=skip_primitive)
+
+ concat = range(2+steps-multiplier, steps+2)
+ genotype = genotypes.Genotype(
+ normal=gene_normal, normal_concat=concat,
+ reduce=gene_reduce, reduce_concat=concat,
+ layout='cell',
+ )
+ return genotype
+
+
+def main():
+ '''
+ Parse raw weights with the hack that excludes the 'none' primitive, and without that hack.
+ Then print out the final genotypes.
+ '''
+ # Set these variables to the ones you're using in this case from genotypes.py
+ skip_primitive = None
+ raw_weights_genotype = genotypes.SHARPER_SCALAR_WEIGHTS
+ primitives = genotypes.SHARPER_PRIMITIVES
+ # get the normal and reduce weights as a numpy array
+ alphas_normal = np.array(raw_weights_genotype.normal)
+ alphas_reduce = np.array(raw_weights_genotype.reduce)
+
+ # for steps, see layers_in_cells in train_search.py
+ steps = 4
+ # for multiplier, see multiplier for Network class in model_search.py
+ multiplier = 4
+ # note the printed weights from a call to Network::arch_weights() in model_search.py
+ # are already post-softmax, so we don't need to apply softmax again
+ # alphas_normal = torch.FloatTensor(genotypes.SHARPER_SCALAR_WEIGHTS.normal)
+ # alphas_reduce = torch.FloatTensor(genotypes.SHARPER_SCALAR_WEIGHTS.reduce)
+ # F.softmax(alphas_normal, dim=-1).data.cpu().numpy()
+ # F.softmax(alphas_reduce, dim=-1).data.cpu().numpy()
+
+ # skip_primitive = 'none' is a hack in original DARTS, which removes a no-op primitive.
+ # skip_primitive = None means no hack is applied
+ print('#################')
+ genotype = genotype_cell(alphas_normal, alphas_reduce, primitives, steps=4, multiplier=4, skip_primitive='none')
+ print('SHARPER_SCALAR_genotype_skip_none = ' + str(genotype))
+ genotype = genotype_cell(alphas_normal, alphas_reduce, primitives, steps=4, multiplier=4, skip_primitive=None)
+ print('SHARPER_SCALAR_genotype_no_hack = ' + str(genotype))
+ # Set these variables to the ones you're using in this case from genotypes.py
+ skip_primitive = None
+ raw_weights_genotype = genotypes.SHARPER_MAX_W_WEIGHTS
+ primitives = genotypes.SHARPER_PRIMITIVES
+ # get the normal and reduce weights as a numpy array
+ alphas_normal = np.array(raw_weights_genotype.normal)
+ alphas_reduce = np.array(raw_weights_genotype.reduce)
+
+ # for steps, see layers_in_cells in train_search.py
+ steps = 4
+ # for multiplier, see multiplier for Network class in model_search.py
+ multiplier = 4
+ # note the printed weights from a call to Network::arch_weights() in model_search.py
+ # are already post-softmax, so we don't need to apply softmax again
+ # alphas_normal = torch.FloatTensor(genotypes.SHARPER_SCALAR_WEIGHTS.normal)
+ # alphas_reduce = torch.FloatTensor(genotypes.SHARPER_SCALAR_WEIGHTS.reduce)
+ # F.softmax(alphas_normal, dim=-1).data.cpu().numpy()
+ # F.softmax(alphas_reduce, dim=-1).data.cpu().numpy()
+
+ # skip_primitive = 'none' is a hack in original DARTS, which removes a no-op primitive.
+ # skip_primitive = None means no hack is applied
+ print('#################')
+ genotype = genotype_cell(alphas_normal, alphas_reduce, primitives, steps=4, multiplier=4, skip_primitive='none')
+ print('SHARPER_MAX_W_genotype_skip_none = ' + str(genotype))
+ genotype = genotype_cell(alphas_normal, alphas_reduce, primitives, steps=4, multiplier=4, skip_primitive=None)
+ print('SHARPER_MAX_W_genotype_no_hack = ' + str(genotype))
+
+if __name__ == '__main__':
+ main()
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index 0e7025b..35c4a35 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -488,6 +488,37 @@
"""
SHARPER_SCALAR = Genotype(normal=[('skip_connect', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), ('skip_connect', 0), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 1), ('dil_flood_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3), ('skip_connect', 4)], reduce_concat=range(2, 6), layout='cell')
+SHARPER_SCALAR_WEIGHTS = Genotype(normal=[[0.1108, 0.0556, 0.0575, 0.2509, 0.1022, 0.0461, 0.0347, 0.0274, 0.0378, 0.2145, 0.0266, 0.0359],
+ [0.3534, 0.0249, 0.0230, 0.0314, 0.1636, 0.0603, 0.0392, 0.0490, 0.0627, 0.1044, 0.0464, 0.0417],
+ [0.5115, 0.0438, 0.0384, 0.0831, 0.0495, 0.0549, 0.0467, 0.0462, 0.0292, 0.0390, 0.0229, 0.0348],
+ [0.6162, 0.0238, 0.0217, 0.0320, 0.0882, 0.0679, 0.0205, 0.0213, 0.0237, 0.0291, 0.0289, 0.0267],
+ [0.7525, 0.0170, 0.0157, 0.0279, 0.0271, 0.0264, 0.0367, 0.0240, 0.0161, 0.0198, 0.0203, 0.0165],
+ [0.3173, 0.0881, 0.0614, 0.1120, 0.0474, 0.0473, 0.0461, 0.0410, 0.0378, 0.0895, 0.0414, 0.0707],
+ [0.3855, 0.0335, 0.0304, 0.0456, 0.0678, 0.0496, 0.0579, 0.0441, 0.0467, 0.1161, 0.0841, 0.0389],
+ [0.5562, 0.0272, 0.0226, 0.0429, 0.0706, 0.0511, 0.0392, 0.0321, 0.0275, 0.0596, 0.0366, 0.0344],
+ [0.1158, 0.0256, 0.0253, 0.0423, 0.1826, 0.0349, 0.0435, 0.0868, 0.0274, 0.0752, 0.1449, 0.1957],
+ [0.2988, 0.0673, 0.0460, 0.0676, 0.0678, 0.0567, 0.0483, 0.0704, 0.0604, 0.1230, 0.0485, 0.0452],
+ [0.3221, 0.0363, 0.0330, 0.0455, 0.0809, 0.0457, 0.0519, 0.0636, 0.0689, 0.1469, 0.0629, 0.0421],
+ [0.4835, 0.0269, 0.0227, 0.0398, 0.0528, 0.0671, 0.0407, 0.0762, 0.0554, 0.0495, 0.0554, 0.0300],
+ [0.0593, 0.0200, 0.0193, 0.0318, 0.0606, 0.0445, 0.0292, 0.0412, 0.0520, 0.1620, 0.0341, 0.4460],
+ [0.0821, 0.0228, 0.0230, 0.0340, 0.1011, 0.0903, 0.0396, 0.1702, 0.0370, 0.1469, 0.0921, 0.1609]],
+ reduce=[[0.0628, 0.2237, 0.1198, 0.0752, 0.0712, 0.0598, 0.0775, 0.0537, 0.0651, 0.0707, 0.0613, 0.0594],
+ [0.0812, 0.1069, 0.1021, 0.1551, 0.0841, 0.0636, 0.0473, 0.0726, 0.0584, 0.0799, 0.0786, 0.0701],
+ [0.0625, 0.1197, 0.1379, 0.0985, 0.1186, 0.0799, 0.0425, 0.0679, 0.0458, 0.0692, 0.0832, 0.0743],
+ [0.0708, 0.0994, 0.1058, 0.1389, 0.0632, 0.0556, 0.0569, 0.0937, 0.0654, 0.1025, 0.0836, 0.0641],
+ [0.0874, 0.0765, 0.0767, 0.1159, 0.0823, 0.1001, 0.0772, 0.0783, 0.0534, 0.1009, 0.0804, 0.0708],
+ [0.0731, 0.0977, 0.1059, 0.1180, 0.0564, 0.1049, 0.0580, 0.0632, 0.0664, 0.0704, 0.0640, 0.1219],
+ [0.0816, 0.1009, 0.1261, 0.0929, 0.0817, 0.0604, 0.0824, 0.0925, 0.0606, 0.0622, 0.0848, 0.0740],
+ [0.0923, 0.0670, 0.0673, 0.0952, 0.1105, 0.0709, 0.0742, 0.0857, 0.1044, 0.0679, 0.0793, 0.0852],
+ [0.0977, 0.0673, 0.0777, 0.1163, 0.0792, 0.0727, 0.0850, 0.0836, 0.1078, 0.0856, 0.0502, 0.0769],
+ [0.0722, 0.1031, 0.1275, 0.0822, 0.0937, 0.0941, 0.0848, 0.0808, 0.0673, 0.0681, 0.0698, 0.0565],
+ [0.0762, 0.1123, 0.1090, 0.0942, 0.0699, 0.0770, 0.0775, 0.0765, 0.0812, 0.0897, 0.0716, 0.0650],
+ [0.0903, 0.0703, 0.0717, 0.1145, 0.0846, 0.0823, 0.0826, 0.0938, 0.0651, 0.0900, 0.0846, 0.0701],
+ [0.0935, 0.0614, 0.0651, 0.1099, 0.1085, 0.0799, 0.0833, 0.0786, 0.0622, 0.1417, 0.0515, 0.0644],
+ [0.1492, 0.0676, 0.0754, 0.1314, 0.0717, 0.1051, 0.0829, 0.0670, 0.0863, 0.0683, 0.0518, 0.0432]], normal_concat=[], reduce_concat=[], layout='raw_weights')
+# Retrieved from SHARPER_SCALAR_WEIGHTS by running genotype_extractor.py
+SHARPER_SCALAR_genotype_skip_none = Genotype(normal=[('skip_connect', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), ('skip_connect', 0), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 1), ('dil_flood_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3), ('skip_connect', 4)], reduce_concat=range(2, 6), layout='cell')
+SHARPER_SCALAR_genotype_no_hack = Genotype(normal=[('none', 1), ('skip_connect', 0), ('none', 2), ('none', 1), ('none', 2), ('none', 1), ('none', 2), ('dil_flood_conv_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('none', 4), ('flood_conv_3x3', 3)], reduce_concat=range(2, 6), layout='cell')
"""
@@ -543,3 +574,34 @@
"""
SHARPER_MAX_W = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
+SHARPER_MAX_W_WEIGHTS = Genotype(normal=[[0.0064, 0.0045, 0.0048, 0.0053, 0.9306, 0.0070, 0.0069, 0.0070, 0.0064, 0.0066, 0.0069, 0.0076],
+ [0.0527, 0.0296, 0.0307, 0.0398, 0.0742, 0.0773, 0.0469, 0.1153, 0.2443, 0.1075, 0.0677, 0.1140],
+ [0.0392, 0.5563, 0.0226, 0.0266, 0.0424, 0.0451, 0.0452, 0.0414, 0.0485, 0.0419, 0.0433, 0.0476],
+ [0.0692, 0.0517, 0.0510, 0.0607, 0.0794, 0.2549, 0.0680, 0.0732, 0.0677, 0.0699, 0.0744, 0.0799],
+ [0.0454, 0.0421, 0.0343, 0.0414, 0.0426, 0.0447, 0.5136, 0.0453, 0.0458, 0.0522, 0.0464, 0.0460],
+ [0.0111, 0.0090, 0.0093, 0.0099, 0.0111, 0.0114, 0.0113, 0.0108, 0.0111, 0.8829, 0.0108, 0.0113],
+ [0.0610, 0.0434, 0.0440, 0.0507, 0.0652, 0.0654, 0.0673, 0.0664, 0.0790, 0.0715, 0.3231, 0.0629],
+ [0.0512, 0.0389, 0.0340, 0.4399, 0.0558, 0.0542, 0.0536, 0.0563, 0.0582, 0.0515, 0.0535, 0.0529],
+ [0.0081, 0.0071, 0.9128, 0.0058, 0.0081, 0.0083, 0.0082, 0.0083, 0.0082, 0.0085, 0.0083, 0.0082],
+ [0.0772, 0.0519, 0.0568, 0.0651, 0.0911, 0.1073, 0.1002, 0.1074, 0.0702, 0.0717, 0.0935, 0.1075],
+ [0.0779, 0.0605, 0.0629, 0.0704, 0.0858, 0.0788, 0.0745, 0.0790, 0.0771, 0.1685, 0.0820, 0.0824],
+ [0.0795, 0.0674, 0.0584, 0.1416, 0.0774, 0.0742, 0.0791, 0.0843, 0.0848, 0.0799, 0.0824, 0.0909],
+ [0.5488, 0.0359, 0.0321, 0.0295, 0.0464, 0.0443, 0.0413, 0.0444, 0.0459, 0.0438, 0.0430, 0.0445],
+ [0.6040, 0.0317, 0.0297, 0.0233, 0.0423, 0.0379, 0.0389, 0.0354, 0.0369, 0.0379, 0.0445, 0.0376]],
+ reduce=[[0.0370, 0.0326, 0.0338, 0.0345, 0.0368, 0.0377, 0.0339, 0.0378, 0.0322, 0.0370, 0.6131, 0.0336],
+ [0.0800, 0.0891, 0.0890, 0.0891, 0.0888, 0.0890, 0.0672, 0.0886, 0.0890, 0.0880, 0.0530, 0.0892],
+ [0.0461, 0.0431, 0.0443, 0.0448, 0.5159, 0.0455, 0.0426, 0.0427, 0.0423, 0.0434, 0.0458, 0.0435],
+ [0.0825, 0.0883, 0.0882, 0.0886, 0.0820, 0.0883, 0.0698, 0.0882, 0.0715, 0.0776, 0.0869, 0.0882],
+ [0.0795, 0.0849, 0.0849, 0.1471, 0.0828, 0.0768, 0.0816, 0.0687, 0.0692, 0.0897, 0.0749, 0.0598],
+ [0.0694, 0.0658, 0.0676, 0.0679, 0.2674, 0.0675, 0.0653, 0.0684, 0.0669, 0.0629, 0.0648, 0.0661],
+ [0.0831, 0.0887, 0.0884, 0.0885, 0.0827, 0.0841, 0.0801, 0.0793, 0.0780, 0.0852, 0.0821, 0.0799],
+ [0.0795, 0.0818, 0.0828, 0.1563, 0.0836, 0.0785, 0.0753, 0.0717, 0.0760, 0.0711, 0.0712, 0.0721],
+ [0.0812, 0.0808, 0.0787, 0.1316, 0.0800, 0.0816, 0.0862, 0.0779, 0.0833, 0.0724, 0.0753, 0.0709],
+ [0.0801, 0.0770, 0.0786, 0.0791, 0.1442, 0.0784, 0.0740, 0.0758, 0.0773, 0.0812, 0.0776, 0.0767],
+ [0.0832, 0.0874, 0.0869, 0.0881, 0.0839, 0.0808, 0.0828, 0.0830, 0.0818, 0.0830, 0.0753, 0.0838],
+ [0.0823, 0.0844, 0.0854, 0.1030, 0.0826, 0.0882, 0.0793, 0.0819, 0.0845, 0.0774, 0.0792, 0.0719],
+ [0.0827, 0.0825, 0.0813, 0.1029, 0.0854, 0.0818, 0.0835, 0.0824, 0.0828, 0.0799, 0.0774, 0.0774],
+ [0.0799, 0.0759, 0.0747, 0.0774, 0.0808, 0.0749, 0.0827, 0.0802, 0.1554, 0.0747, 0.0713, 0.0722]], normal_concat=[], reduce_concat=[], layout='raw_weights')
+# Retrieved from SHARPER_MAX_W_WEIGHTS by running genotype_extractor.py
+SHARPER_MAX_W_genotype_skip_none = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
+SHARPER_MAX_W_genotype_no_hack = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('none', 4), ('none', 3)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
\ No newline at end of file
diff --git a/cnn/model_search.py b/cnn/model_search.py
index dd63d9d..6b28fc2 100644
--- a/cnn/model_search.py
+++ b/cnn/model_search.py
@@ -11,6 +11,7 @@
from networkx.readwrite import json_graph
import json
import time
+import genotype_extractor
class MixedOp(nn.Module):
@@ -203,54 +204,20 @@ def arch_weights(self, stride_idx):
weights = F.softmax(weights_softmax_view, dim=-1)
return weights
- def genotype(self):
-
- def _parse(weights):
- """ Take a weight array and turn it into a list of pairs (primitive_string, node_index).
- """
- gene = []
- n = 2
- start = 0
- for i in range(self._steps):
- # Each step is a separate "add node" in the graph, so i is the integer index of the current node.
- # A better name for i might be add_node_index.
- end = start + n
- # Only look at the weights relevant to this node.
- # "Nodes" 0 and 1 will always be the output of the previous cells.
- #
- # All other nodes will be add nodes which need edges connecting back to the previous nodes:
- # add node 0 will need 2: rows 0, 1
- # add node 1 will need 3: rows 2, 3, 4
- # add node 2 will need 4: rows 5, 6, 7, 8
- # add node 3 will need 5: rows 9, 10, 11, 12, 13
- # ...and so on if there are more than 4 nodes.
- W = weights[start:end].copy()
- # Each row in the weights is a separate edge, and each column are the possible primitives that edge might use.
- # The first "add node" can connect back to the two previous cells, which is why the edges are i + 2.
- # The sorted function orders lists from lowest to highest, so we use -max in the lambda function to sort from highest to lowest.
- # We currently say there will only be two edges connecting to each node, which is why there is [:2], to select the two highest score edges.
- # Each later nodes can connect back to the previous cells or an internal node, so the range(i+2) of possible connections increases.
- edges = sorted(range(i + 2), key=lambda x: -max(W[x][k] for k in range(len(W[x])) if k != self.primitives.index('none')))[:2]
- # We've now selected the two edges we will use for this node, so next let's select the layer primitives.
- # Each edge needs a particular primitive, so go through all the edges and compare all the possible primitives.
- for j in edges:
- k_best = None
- # note: This probably could be simpler via argmax...
- # Loop through all the columns to find the highest score primitive for the chosen edge, excluding none.
- for k in range(len(W[j])):
- if k != self.primitives.index('none'):
- if k_best is None or W[j][k] > W[j][k_best]:
- k_best = k
- # Once the best primitive is chosen, create the new gene element, which is the
- # string for the name of the primitive, and the index of the previous node to connect to,
- gene.append((self.primitives[k_best], j))
- start = end
- n += 1
- # Return the full list of (node, primitive) pairs for this set of weights.
- return gene
-
- gene_normal = _parse(F.softmax(self.alphas_normal, dim=-1).data.cpu().numpy())
- gene_reduce = _parse(F.softmax(self.alphas_reduce, dim=-1).data.cpu().numpy())
+ def genotype(self, skip_primitive='none'):
+ '''
+ Extract the genotype, or specific connections within a cell, as encoded by the weights.
+ # Arguments
+ skip_primitives: hack was added by DARTS to temporarily workaround the
+ 'strong gradient' problem identified in the sharpDARTS paper https://arxiv.org/abs/1903.09900,
+ set skip_primitive=None to not skip any primitives.
+ '''
+ gene_normal = genotype_extractor.parse_cell(
+ F.softmax(self.alphas_normal, dim=-1).data.cpu().numpy(),
+ primitives=self.primitives, steps=self._steps, skip_primitive=skip_primitive)
+ gene_reduce = genotype_extractor.parse_cell(
+ F.softmax(self.alphas_reduce, dim=-1).data.cpu().numpy(),
+ primitives=self.primitives, steps=self._steps, skip_primitive=skip_primitive)
concat = range(2+self._steps-self._multiplier, self._steps+2)
genotype = Genotype(
@@ -569,7 +536,7 @@ def forward(self, input_batch):
# print('logits')
#print("Optimal_path_forward", nx.algorithms.dag.dag_longest_path(self.G))
#print("Top down greedy", self.gen_greedy_path(self.G,"top_down"))
- #print("Bottom up greedy",self.gen_greedy_path(self.G,"bottom_up"))
+ #print("Bottom up greedy",self.gen_greedy_path(self.G,"bottom_up"))
return logits
def gen_greedy_path(self, G, strategy="top_down"):
@@ -626,7 +593,7 @@ def _loss(self, input_batch, target):
return self._criterion(logits, target)
def _initialize_alphas(self, genotype=None):
-
+
if genotype is None or genotype[-1] == 'longest_path':
init_alpha = 1e-3*torch.randn(self.arch_weights_shape)
else:
From d7791b5de9a0179ede303912bdeb6bb17520c48d Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Sun, 12 May 2019 12:40:00 -0400
Subject: [PATCH 18/40] cnn/visualize.py different genotypes get different
filenames
---
cnn/visualize.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/cnn/visualize.py b/cnn/visualize.py
index d599e6c..c372e34 100644
--- a/cnn/visualize.py
+++ b/cnn/visualize.py
@@ -47,9 +47,9 @@ def plot(genotype, filename):
try:
genotype = eval('genotypes.{}'.format(genotype_name))
except AttributeError:
- print("{} is not specified in genotypes.py".format(genotype_name))
+ print("{} is not specified in genotypes.py".format(genotype_name))
sys.exit(1)
- plot(genotype.normal, "normal")
- plot(genotype.reduce, "reduction")
+ plot(genotype.normal, genotype_name + "_normal")
+ plot(genotype.reduce, genotype_name + "_reduction")
From f0f88d65ff5979406c2139a3acbb7db9e7eb93ea Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Wed, 15 May 2019 13:41:01 -0400
Subject: [PATCH 19/40] README.md first sharpDARTS readme
---
README.md | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 86 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 3f711a0..67582e8 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,89 @@
-# Differentiable Architecture Search
+# sharpDARTS: Faster, More Accurate Differentiable Architecture Search
+
+Please cite sharpDARTS if you use this code as part of your research! By using any part of the code you are agreeing to comply with our permissive Apache 2.0 license.
+
+```
+@article{DBLP:journals/corr/abs-1903-09900,
+ author = {Andrew Hundt and
+ Varun Jain and
+ Gregory D. Hager},
+ title = {sharpDARTS: Faster and More Accurate Differentiable Architecture Search},
+ journal = {CoRR},
+ volume = {abs/1903.09900},
+ year = {2019},
+ url = {http://arxiv.org/abs/1903.09900},
+ archivePrefix = {arXiv},
+ eprint = {1903.09900},
+ biburl = {https://dblp.org/rec/bib/journals/corr/abs-1903-09900},
+ bibsource = {dblp computer science bibliography, https://dblp.org}
+}
+```
+
+For algorithm details see:
+[sharpDARTS: Faster, More Accurate Differentiable Architecture Search](http://arxiv.org/abs/1903.09900)
+
+Requires pytorch 1.0.
+
+
+## Searching for a model
+
+To see the configuration options, run `python3 train_search.py --help` from the directory `cnn`. The code is also commented.
+
+Run `cnn/train_search.py` with your configuration. Place the best genotype into `genotypes.py`, preferably with a record of the raw weights as well and other command execution data so similar results can be reproduced in the future.
+
+## Training a final Model
+
+To see the configuration options, run `python3 train.py --help` from the directory `cnn`. The code is also commented.
+
+### CIFAR-10 Training
+
+Best Results with SharpSepConvDARTS:
+```
+export CUDA_VISIBLE_DEVICES="0" && python3 train.py --autoaugment --auxiliary --cutout --batch_size 64 --epochs 2000 --save SHARPSEPCONV_DARTS_2k_`git rev-parse --short HEAD`_cospower_min_1e-8 --arch SHARPSEPCONV_DARTS --learning_rate 0.025 --learning_rate_min 1e-8 --cutout_length 16 --init_channels 36 --dataset cifar10
+```
+
+Collecting multiple data points:
+
+```
+for i in {1..8}; do export CUDA_VISIBLE_DEVICES="0" && python3 train.py --autoaugment --auxiliary --cutout --batch_size 64 --epochs 2000 --save SHARPSEPCONV_DARTS_MAX_W_2k_`git rev-parse --short HEAD`_cospower_min_1e-8 --learning_rate 0.025 --learning_rate_min 1e-8 --cutout_length 16 --init_channels 36 --dataset cifar10 --arch SHARPSEPCONV_DARTS_MAX_W ; done;
+```
+
+
+### ImageNet Training
+
+We train with a modified version the fp16 optimizer from [APEX](https://github.com/NVIDIA/apex), we suspect this means results will be slightly below the ideal possible accuracy, but training time is substantially reduced.
+These configurations are designed for an NVIDIA RTX 1080Ti, `--fp16` should be removed for older GPUs.
+
+You'll need to first [acquire the imagenet files](http://image-net.org/download) and preprocess them.
+
+Best SharpSepConvDARTS Results:
+
+```
+python3 -m torch.distributed.launch --nproc_per_node=2 main_fp16_optimizer.py --fp16 --b 224 --save `git rev-parse --short HEAD`_DARTS_PRIMITIVES_DIL_IS_SEPCONV --epochs 300 --dynamic-loss-scale --workers 20 --autoaugment --auxiliary --cutout --data /home/costar/datasets/imagenet/ --learning_rate 0.05 --learning_rate_min 0.00075 --arch DARTS_PRIMITIVES_DIL_IS_SEPCONV
+```
+
+Resuming Training (you may need to do this if your results don't match the paper on the first run):
+
+You'll need to make sure to specify the correct checkpoint directory, which will change every run.
+```
+python3 -m torch.distributed.launch --nproc_per_node=2 main_fp16_optimizer.py --fp16 --b 224 --save `git rev-parse --short HEAD`_DARTS_PRIMITIVES_DIL_IS_SEPCONV --epochs 100 --dynamic-loss-scale --workers 20 --autoaugment --auxiliary --cutout --data /home/costar/datasets/imagenet/ --learning_rate 0.0005 --learning_rate_min 0.0000075 --arch DARTS_PRIMITIVES_DIL_IS_SEPCONV --resume eval-20190213-182625-975c657_DARTS_PRIMITIVES_DIL_IS_SEPCONV-imagenet-DARTS_PRIMITIVES_DIL_IS_SEPCONV-0/checkpoint.pth.tar
+```
+
+Training SHARP_DARTS model on ImageNet:
+
+```
+export CUDA_VISIBLE_DEVICES="0" && python3 main_fp16_optimizer.py --fp16 --b 256 --save `git rev-parse --short HEAD` --epochs 400 --dynamic-loss-scale --workers 20 --autoaugment --auxiliary --cutout --data /home/costar/datasets/imagenet/ --learning_rate_min 1e-8 --mid_channels 96 --lr 1e-4 --load eval-20190222-175718-4f5892f-imagenet-SHARP_DARTS-0/model_best.pth.tar
+```
+
+### Differentiable Hyperparameter Search
+
+```
+export CUDA_VISIBLE_DEVICES="1" && python2 train_search.py --dataset cifar10 --batch_size 64 --save MULTI_CHANNEL_SEARCH_`git rev-parse --short HEAD`_search_weighting_max_w --init_channels 36 --epochs 120 --cutout --autoaugment --seed 10 --weighting_algorithm max_w --multi_channel
+```
+
+
+# sharpDARTS Repository based on Differentiable Architecture Search (DARTS)
+
Code accompanying the paper
> [DARTS: Differentiable Architecture Search](https://arxiv.org/abs/1806.09055)\
> Hanxiao Liu, Karen Simonyan, Yiming Yang.\
From b374f37768bdcbefb8eef9c0afcc867600d0e6cb Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Wed, 15 May 2019 14:01:22 -0400
Subject: [PATCH 20/40] train.py add SHARPER_PRIMITIVES option to help
---
cnn/train.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cnn/train.py b/cnn/train.py
index 7da376a..8d5151a 100644
--- a/cnn/train.py
+++ b/cnn/train.py
@@ -67,7 +67,7 @@ def main():
parser.add_argument('--ops', type=str, default='OPS', help='which operations to use, options are OPS and DARTS_OPS')
parser.add_argument('--primitives', type=str, default='PRIMITIVES',
help='which primitive layers to use inside a cell search space,'
- ' options are PRIMITIVES and DARTS_PRIMITIVES')
+ ' options are PRIMITIVES, SHARPER_PRIMITIVES, and DARTS_PRIMITIVES')
parser.add_argument('--optimizer', type=str, default='sgd', help='which optimizer to use, options are padam and sgd')
parser.add_argument('--load', type=str, default='', metavar='PATH', help='load weights at specified location')
parser.add_argument('--grad_clip', type=float, default=5, help='gradient clipping')
From fc7909153c9c07d4789c71bf2b7d995364478c35 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Wed, 15 May 2019 14:28:31 -0400
Subject: [PATCH 21/40] genotypes.py update sharper no hacks run command
---
cnn/genotypes.py | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/cnn/genotypes.py b/cnn/genotypes.py
index 35c4a35..b1801e0 100644
--- a/cnn/genotypes.py
+++ b/cnn/genotypes.py
@@ -518,6 +518,19 @@
[0.1492, 0.0676, 0.0754, 0.1314, 0.0717, 0.1051, 0.0829, 0.0670, 0.0863, 0.0683, 0.0518, 0.0432]], normal_concat=[], reduce_concat=[], layout='raw_weights')
# Retrieved from SHARPER_SCALAR_WEIGHTS by running genotype_extractor.py
SHARPER_SCALAR_genotype_skip_none = Genotype(normal=[('skip_connect', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), ('skip_connect', 0), ('dil_flood_conv_3x3', 3), ('flood_conv_3x3', 1), ('dil_flood_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('flood_conv_3x3', 3), ('skip_connect', 4)], reduce_concat=range(2, 6), layout='cell')
+"""
+costar@ubuntu|/media/costar/7d094c19-d61f-48fe-93cb-0f7287e05292/datasets/sharpDARTS/cnn on sharper!?
+± for i in {1..8}; do export CUDA_VISIBLE_DEVICES="0" && python3 train.py --autoaugment --auxiliary --cutout --batch_size 64 --epochs 2000 --save SHARPER_SCALAR_genotype_no_hack_2k_`git rev-parse --short HEAD`_cospower_min_1e-8 --learning_rate 0.025 --learning_rate_min 1e-8 --cutout_length 16 --init_channels 36 --dataset cifar10 --arch SHARPER_SCALAR_genotype_no_hack --primitives SHARPER_PRIMITIVES ; done;
+Tensorflow is not installed. Skipping tf related imports
+Experiment dir : eval-20190515-140449-SHARPER_SCALAR_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_SCALAR_genotype_no_hack-0
+2019_05_15_14_04_49 gpu device = 0
+2019_05_15_14_04_49 args = Namespace(arch='SHARPER_SCALAR_genotype_no_hack', autoaugment=True, auxiliary=True, auxiliary_weight=0.4, batch_size=64, cutout=True, cutout_length=16, data='../data', dataset='cifar10', drop_path_prob=0.2, epoch_stats_file='eval-20190515-140449-SHARPER_SCALAR_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_SCALAR_genotype_no_hack-0/eval-epoch-stats-20190515-140449.json', epochs=2000, evaluate='', flops=False, gpu=0, grad_clip=5, init_channels=36, layers=20, layers_in_cells=4, layers_of_cells=8, learning_rate=0.025, learning_rate_min=1e-08, load='', load_args='', load_genotype=None, log_file_path='eval-20190515-140449-SHARPER_SCALAR_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_SCALAR_genotype_no_hack-0/log.txt', lr_power_annealing_exponent_order=2, mid_channels=32, mixed_auxiliary=False, model_path='saved_models', momentum=0.9, multi_channel=False, ops='OPS', optimizer='sgd', partial=0.125, primitives='SHARPER_PRIMITIVES', random_eraser=False, report_freq=50, save='eval-20190515-140449-SHARPER_SCALAR_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_SCALAR_genotype_no_hack-0', seed=0, start_epoch=1, stats_file='eval-20190515-140449-SHARPER_SCALAR_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_SCALAR_genotype_no_hack-0/eval-stats-20190515-140449.json', warm_restarts=20, warmup_epochs=5, weight_decay=0.0003, weighting_algorithm='scalar')
+2019_05_15_14_04_49 output channels: 10
+2019_05_15_14_04_49 loading op dict: operations.OPS
+2019_05_15_14_04_49 loading primitives:genotypes.SHARPER_PRIMITIVES
+2019_05_15_14_04_49 primitives: ['none', 'max_pool_3x3', 'avg_pool_3x3', 'skip_connect', 'sep_conv_3x3', 'sep_conv_5x5', 'sep_conv_7x7', 'dil_conv_3x3', 'dil_conv_5x5', 'flood_conv_3x3', 'flood_conv_5x5', 'dil_flood_conv_3x3']
+2019_05_15_14_04_51 param size = 3.250846MB
+"""
SHARPER_SCALAR_genotype_no_hack = Genotype(normal=[('none', 1), ('skip_connect', 0), ('none', 2), ('none', 1), ('none', 2), ('none', 1), ('none', 2), ('dil_flood_conv_3x3', 3)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('skip_connect', 1), ('skip_connect', 1), ('avg_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_flood_conv_3x3', 0), ('none', 4), ('flood_conv_3x3', 3)], reduce_concat=range(2, 6), layout='cell')
"""
@@ -604,4 +617,19 @@
[0.0799, 0.0759, 0.0747, 0.0774, 0.0808, 0.0749, 0.0827, 0.0802, 0.1554, 0.0747, 0.0713, 0.0722]], normal_concat=[], reduce_concat=[], layout='raw_weights')
# Retrieved from SHARPER_MAX_W_WEIGHTS by running genotype_extractor.py
SHARPER_MAX_W_genotype_skip_none = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('flood_conv_3x3', 1), ('skip_connect', 2)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
+"""
+costar@ubuntu|/media/costar/7d094c19-d61f-48fe-93cb-0f7287e05292/datasets/sharpDARTS/cnn on sharper!?
+± for i in {1..8}; do export CUDA_VISIBLE_DEVICES="1" && python3 train.py --autoaugment --auxiliary --cutout --batch_size 48 --epochs 2000 --save SHARPER_MAX_W_genotype_no_hack_2k_`git rev-parse --short HEAD`_cospower_min_1e-8 --learning_rate 0.025 --learning_rate_min 1e-8 --cutout_length 16 --init_channels 36 --dataset cifar10 --arch SHARPER_MAX_W_genotype_no_hack --primitives SHARPER_PRIMITIVES ; done;
+Tensorflow is not installed. Skipping tf related imports
+Experiment dir : eval-20190515-142614-SHARPER_MAX_W_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_MAX_W_genotype_no_hack-0
+2019_05_15_14_26_14 gpu device = 0
+2019_05_15_14_26_14 args = Namespace(arch='SHARPER_MAX_W_genotype_no_hack', autoaugment=True, auxiliary=True, auxiliary_weight=0.4, batch_size=48, cutout=True, cutout_length=16, data='../data', dataset='cifar10', drop_path_prob=0.2, epoch_stats_file='eval-20190515-142614-SHARPER_MAX_W_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_MAX_W_genotype_no_hack-0/eval-epoch-stats-20190515-142614.json', epochs=2000, evaluate='', flops=False, gpu=0, grad_clip=5, init_channels=36, layers=20, layers_in_cells=4, layers_of_cells=8, learning_rate=0.025, learning_rate_min=1e-08, load='', load_args='', load_genotype=None, log_file_path='eval-20190515-142614-SHARPER_MAX_W_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_MAX_W_genotype_no_hack-0/log.txt', lr_power_annealing_exponent_order=2, mid_channels=32, mixed_auxiliary=False, model_path='saved_models', momentum=0.9, multi_channel=False, ops='OPS', optimizer='sgd', partial=0.125, primitives='SHARPER_PRIMITIVES', random_eraser=False, report_freq=50, save='eval-20190515-142614-SHARPER_MAX_W_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_MAX_W_genotype_no_hack-0', seed=0, start_epoch=1, stats_file='eval-20190515-142614-SHARPER_MAX_W_genotype_no_hack_2k_b374f37_cospower_min_1e-8-cifar10-SHARPER_MAX_W_genotype_no_hack-0/eval-stats-20190515-142614.json', warm_restarts=20, warmup_epochs=5, weight_decay=0.0003, weighting_algorithm='scalar')
+2019_05_15_14_26_14 output channels: 10
+2019_05_15_14_26_14 loading op dict: operations.OPS
+2019_05_15_14_26_14 loading primitives:genotypes.SHARPER_PRIMITIVES
+2019_05_15_14_26_14 primitives: ['none', 'max_pool_3x3', 'avg_pool_3x3', 'skip_connect', 'sep_conv_3x3', 'sep_conv_5x5', 'sep_conv_7x7', 'dil_conv_3x3', 'dil_conv_5x5', 'flood_conv_3x3', 'flood_conv_5x5', 'dil_flood_conv_3x3']
+2019_05_15_14_26_17 param size = 4.697614MB
+
+
+"""
SHARPER_MAX_W_genotype_no_hack = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('max_pool_3x3', 0), ('sep_conv_7x7', 2), ('avg_pool_3x3', 3), ('flood_conv_3x3', 0), ('none', 4), ('none', 3)], normal_concat=range(2, 6), reduce=[('flood_conv_5x5', 0), ('dil_flood_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2), ('sep_conv_3x3', 0), ('skip_connect', 2), ('dil_conv_5x5', 4), ('sep_conv_3x3', 0)], reduce_concat=range(2, 6), layout='cell')
\ No newline at end of file
From 72601bdbf71a8c1aa12dadf486d4960b48656052 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Wed, 15 May 2019 14:57:55 -0400
Subject: [PATCH 22/40] README.md ack-grep command
---
README.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 67582e8..7b1e902 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,10 @@ Collecting multiple data points:
for i in {1..8}; do export CUDA_VISIBLE_DEVICES="0" && python3 train.py --autoaugment --auxiliary --cutout --batch_size 64 --epochs 2000 --save SHARPSEPCONV_DARTS_MAX_W_2k_`git rev-parse --short HEAD`_cospower_min_1e-8 --learning_rate 0.025 --learning_rate_min 1e-8 --cutout_length 16 --init_channels 36 --dataset cifar10 --arch SHARPSEPCONV_DARTS_MAX_W ; done;
```
+Collecting results from multiple runs into a file from `sharperDARTS/cnn` directory with [ack-grep](https://beyondgrep.com/) (on some machiens it is just `ack`):
+```
+ack-grep --match "cifar10.1" */*.txt > cifar10.1_results_femur.txt
+```
### ImageNet Training
@@ -64,7 +68,7 @@ python3 -m torch.distributed.launch --nproc_per_node=2 main_fp16_optimizer.py --
Resuming Training (you may need to do this if your results don't match the paper on the first run):
-You'll need to make sure to specify the correct checkpoint directory, which will change every run.
+You'll need to make sure to specify the correct checkpoint directory, which will change every run.
```
python3 -m torch.distributed.launch --nproc_per_node=2 main_fp16_optimizer.py --fp16 --b 224 --save `git rev-parse --short HEAD`_DARTS_PRIMITIVES_DIL_IS_SEPCONV --epochs 100 --dynamic-loss-scale --workers 20 --autoaugment --auxiliary --cutout --data /home/costar/datasets/imagenet/ --learning_rate 0.0005 --learning_rate_min 0.0000075 --arch DARTS_PRIMITIVES_DIL_IS_SEPCONV --resume eval-20190213-182625-975c657_DARTS_PRIMITIVES_DIL_IS_SEPCONV-imagenet-DARTS_PRIMITIVES_DIL_IS_SEPCONV-0/checkpoint.pth.tar
```
From ee54e5913e7b5cc58ff5ef03333ce21df13d6dfb Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Wed, 15 May 2019 15:02:59 -0400
Subject: [PATCH 23/40] README.md add differentiable hyperparameter search
---
README.md | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 7b1e902..57e1290 100644
--- a/README.md
+++ b/README.md
@@ -79,12 +79,19 @@ Training SHARP_DARTS model on ImageNet:
export CUDA_VISIBLE_DEVICES="0" && python3 main_fp16_optimizer.py --fp16 --b 256 --save `git rev-parse --short HEAD` --epochs 400 --dynamic-loss-scale --workers 20 --autoaugment --auxiliary --cutout --data /home/costar/datasets/imagenet/ --learning_rate_min 1e-8 --mid_channels 96 --lr 1e-4 --load eval-20190222-175718-4f5892f-imagenet-SHARP_DARTS-0/model_best.pth.tar
```
-### Differentiable Hyperparameter Search
+## Differentiable Hyperparameter Search on CIFAR-10
+Searching for a Model:
```
export CUDA_VISIBLE_DEVICES="1" && python2 train_search.py --dataset cifar10 --batch_size 64 --save MULTI_CHANNEL_SEARCH_`git rev-parse --short HEAD`_search_weighting_max_w --init_channels 36 --epochs 120 --cutout --autoaugment --seed 10 --weighting_algorithm max_w --multi_channel
```
+Add the best path printed during the search process to `genotypes.py`, you can see examples in that file.
+
+Training a final model, this one will reproduce the best results from Max-W search:
+```
+for i in {1..5}; do export CUDA_VISIBLE_DEVICES="0" && python3 train.py --b 512 --save MULTI_CHANNEL_MAX_W_PATH_FULL_2k_`git rev-parse --short HEAD`_LR_0.1_to_1e-8 --arch MULTI_CHANNEL_MAX_W_PATH --epochs 2000 --multi_channel --cutout --autoaugment --learning_rate 0.1 ; done;
+```
# sharpDARTS Repository based on Differentiable Architecture Search (DARTS)
From 6904ca277abcb86bda1c8068ee280c6577606395 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Wed, 15 May 2019 15:08:28 -0400
Subject: [PATCH 24/40] README.md explain cosine power annealing
---
README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/README.md b/README.md
index 57e1290..242e30b 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,67 @@ Training a final model, this one will reproduce the best results from Max-W sear
for i in {1..5}; do export CUDA_VISIBLE_DEVICES="0" && python3 train.py --b 512 --save MULTI_CHANNEL_MAX_W_PATH_FULL_2k_`git rev-parse --short HEAD`_LR_0.1_to_1e-8 --arch MULTI_CHANNEL_MAX_W_PATH --epochs 2000 --multi_channel --cutout --autoaugment --learning_rate 0.1 ; done;
```
+## Cosine Power Annealing
+
+Cosine Power annealing is designed to be a learning rate schedule which improves on cosine annealing.
+See `consine_power_annealing.py` for the code, and `cnn/train.py` for an example of using the API.
+
+```python
+def cosine_power_annealing(
+ epochs=None, max_lr=0.1, min_lr=1e-4, exponent_order=10,
+ max_epoch=None, warmup_epochs=None, return_intermediates=False,
+ start_epoch=1, restart_lr=True):
+ """ Cosine Power annealing is designed to be an improvement on cosine annealing.
+
+ Often the cosine annealing schedule decreases too slowly at the beginning
+ and to quickly at the end. A simple exponential annealing curve does the
+ opposite, decreasing too quickly at the beginning and too slowly at the end.
+ Power cosine annealing strikes a configurable balance between the two.
+ The larger the exponent order, the faster exponential decay occurs.
+ The smaller the exponent order, the more like cosine annealing the curve becomes.
+
+ # Arguments
+
+ epochs: An integer indicating the number of epochs to train.
+ If you are resuming from epoch 100 and want to run until epoch 300,
+ specify 200.
+ max_lr: The maximum learning rate which is also the initial learning rate.
+ min_lr: The minimum learning rate which is also the final learning rate.
+ exponent_order: Determines how fast the learning rate decays.
+ A value of 1 will perform standard cosine annealing, while
+ 10 will decay with an exponential base of 10.
+ max_epoch: The maximum epoch number that will be encountered.
+ This is usually specified for when you are getting a single learning rate
+ value at the current epoch, or for resuming training runs.
+ return_intermediates: True changes the return value to be
+ [cos_power_annealing, cos_power_proportions, cos_proportions]
+ which is useful for comparing, understanding, and plotting several possible
+ learning rate curves. False returns only the cos_power_annealing
+ learning rate values.,
+ start_epoch: The epoch number to start training from which will be at index 0
+ of the returned numpy array.
+ restart_lr: If True the training curve will be returned as if starting from
+ epoch 1, even if you are resuming from a later epoch. Otherwise we will
+ return with the learning rate as if you have already trained up to
+ the value specified by start_epoch.
+
+ # Returns
+
+ A 1d numpy array cos_power_annealing, which will contain the learning
+ rate you should use at each of the specified epochs.
+ """
+```
+
+Here is the key line with the settings you'll want to use:
+
+```python
+ lr_schedule = cosine_power_annealing(
+ epochs=args.epochs, max_lr=args.learning_rate, min_lr=args.learning_rate_min,
+ warmup_epochs=args.warmup_epochs, exponent_order=args.lr_power_annealing_exponent_order)
+```
+
+lr_schedule is a numpy array containing the learning rate at each epoch.
+
# sharpDARTS Repository based on Differentiable Architecture Search (DARTS)
Code accompanying the paper
From 9cd0551af62abffbcae65bd6f5ffd5cfd9aeba62 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Thu, 30 May 2019 13:26:20 -0400
Subject: [PATCH 25/40] cnn/visualize.py improve viz to make sense
---
cnn/visualize.py | 14 +++++++++-----
cnn/visualize_all.sh | 5 +++++
2 files changed, 14 insertions(+), 5 deletions(-)
create mode 100644 cnn/visualize_all.sh
diff --git a/cnn/visualize.py b/cnn/visualize.py
index c372e34..7afa430 100644
--- a/cnn/visualize.py
+++ b/cnn/visualize.py
@@ -11,13 +11,14 @@ def plot(genotype, filename):
engine='dot')
g.body.extend(['rankdir=LR'])
- g.node("c_{k-2}", fillcolor='darkseagreen2')
- g.node("c_{k-1}", fillcolor='darkseagreen2')
+ g.node(str(0), label="c_{k-2}", fillcolor='darkseagreen2')
+ g.node(str(1), label="c_{k-1}", fillcolor='darkseagreen2')
assert len(genotype) % 2 == 0
steps = len(genotype) // 2
for i in range(steps):
- g.node(str(i), fillcolor='lightblue')
+ g.node(str(i), label='+', fillcolor='lightblue')
+ # g.node(str(i), label='+_{' + str(i) + '}', fillcolor='lightblue')
for i in range(steps):
for k in [2*i, 2*i + 1]:
@@ -29,11 +30,14 @@ def plot(genotype, filename):
else:
u = str(j-2)
v = str(i)
- g.edge(u, v, label=op, fillcolor="gray")
+ name_ijk = str(i) + '_' + str(j) + '_' + str(k) + op
+ g.node(name_ijk, label=op, fillcolor='darkseagreen2')
+ g.edge(u, name_ijk, fillcolor="black")
+ g.edge(name_ijk, v, fillcolor="black")
g.node("c_{k}", fillcolor='palegoldenrod')
for i in range(steps):
- g.edge(str(i), "c_{k}", fillcolor="gray")
+ g.edge(str(i), "c_{k}", fillcolor="black")
g.render(filename, view=True)
diff --git a/cnn/visualize_all.sh b/cnn/visualize_all.sh
new file mode 100644
index 0000000..ffcbbad
--- /dev/null
+++ b/cnn/visualize_all.sh
@@ -0,0 +1,5 @@
+
+python3 visualize.py SHARPER_SCALAR_genotype_skip_none
+python3 visualize.py SHARPER_SCALAR_genotype_no_hack
+python3 visualize.py SHARPER_MAX_W_genotype_no_hack
+python3 visualize.py SHARPER_MAX_W_genotype_skip_none
\ No newline at end of file
From 690f581e2cabbafe15dfcd42d34a74945680041c Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Thu, 30 May 2019 15:21:07 -0400
Subject: [PATCH 26/40] LICENSE copyright update
---
LICENSE | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/LICENSE b/LICENSE
index c440a85..c95e646 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
- Copyright (c) 2018, Hanxiao Liu.
+ Copyright (c) 2019 Andrew Hundt, Varun Jain, and the Code Authors. Copyright (c) 2018, Hanxiao Liu.
All rights reserved.
Apache License
From 4415de83b072a76fdb4539cb8d92b146e40cb33b Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Thu, 30 May 2019 16:32:12 -0400
Subject: [PATCH 27/40] dataset.py reference source for some lines in this file
---
cnn/dataset.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/cnn/dataset.py b/cnn/dataset.py
index df9f6fd..58240cd 100644
--- a/cnn/dataset.py
+++ b/cnn/dataset.py
@@ -1,3 +1,6 @@
+# Code to load various datasets for training.
+#
+# Some data loading code is from https://github.com/DRealArun/darts/ with the same license as DARTS.
import os
import sys
import time
From 45a1bd2bd8d2b1a30e0ff52acd82f8ca6f9ec2d5 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Thu, 30 May 2019 13:26:20 -0400
Subject: [PATCH 28/40] cnn/visualize.py improve viz to make sense
---
cnn/visualize.py | 14 +++++++++-----
cnn/visualize_all.sh | 5 +++++
2 files changed, 14 insertions(+), 5 deletions(-)
create mode 100644 cnn/visualize_all.sh
diff --git a/cnn/visualize.py b/cnn/visualize.py
index c372e34..7afa430 100644
--- a/cnn/visualize.py
+++ b/cnn/visualize.py
@@ -11,13 +11,14 @@ def plot(genotype, filename):
engine='dot')
g.body.extend(['rankdir=LR'])
- g.node("c_{k-2}", fillcolor='darkseagreen2')
- g.node("c_{k-1}", fillcolor='darkseagreen2')
+ g.node(str(0), label="c_{k-2}", fillcolor='darkseagreen2')
+ g.node(str(1), label="c_{k-1}", fillcolor='darkseagreen2')
assert len(genotype) % 2 == 0
steps = len(genotype) // 2
for i in range(steps):
- g.node(str(i), fillcolor='lightblue')
+ g.node(str(i), label='+', fillcolor='lightblue')
+ # g.node(str(i), label='+_{' + str(i) + '}', fillcolor='lightblue')
for i in range(steps):
for k in [2*i, 2*i + 1]:
@@ -29,11 +30,14 @@ def plot(genotype, filename):
else:
u = str(j-2)
v = str(i)
- g.edge(u, v, label=op, fillcolor="gray")
+ name_ijk = str(i) + '_' + str(j) + '_' + str(k) + op
+ g.node(name_ijk, label=op, fillcolor='darkseagreen2')
+ g.edge(u, name_ijk, fillcolor="black")
+ g.edge(name_ijk, v, fillcolor="black")
g.node("c_{k}", fillcolor='palegoldenrod')
for i in range(steps):
- g.edge(str(i), "c_{k}", fillcolor="gray")
+ g.edge(str(i), "c_{k}", fillcolor="black")
g.render(filename, view=True)
diff --git a/cnn/visualize_all.sh b/cnn/visualize_all.sh
new file mode 100644
index 0000000..ffcbbad
--- /dev/null
+++ b/cnn/visualize_all.sh
@@ -0,0 +1,5 @@
+
+python3 visualize.py SHARPER_SCALAR_genotype_skip_none
+python3 visualize.py SHARPER_SCALAR_genotype_no_hack
+python3 visualize.py SHARPER_MAX_W_genotype_no_hack
+python3 visualize.py SHARPER_MAX_W_genotype_skip_none
\ No newline at end of file
From a4e9ac033ab3557a26fb050daa4f7cc9ae97b4a5 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Thu, 30 May 2019 16:51:46 -0400
Subject: [PATCH 29/40] README.md updated with new details
---
README.md | 96 ++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 70 insertions(+), 26 deletions(-)
diff --git a/README.md b/README.md
index 242e30b..fb37f03 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
# sharpDARTS: Faster, More Accurate Differentiable Architecture Search
-Please cite sharpDARTS if you use this code as part of your research! By using any part of the code you are agreeing to comply with our permissive Apache 2.0 license.
+Please cite [sharpDARTS: Faster, More Accurate Differentiable Architecture Search](http://arxiv.org/abs/1903.09900) if you use this code as part of your research! By using any part of the code you are agreeing to comply with our permissive Apache 2.0 license.
```
-@article{DBLP:journals/corr/abs-1903-09900,
+@article{hundt2019sharpdarts,
author = {Andrew Hundt and
Varun Jain and
Gregory D. Hager},
@@ -19,25 +19,45 @@ Please cite sharpDARTS if you use this code as part of your research! By using a
}
```
-For algorithm details see:
-[sharpDARTS: Faster, More Accurate Differentiable Architecture Search](http://arxiv.org/abs/1903.09900)
-
-Requires pytorch 1.0.
-
+Requires pytorch 1.0. References and licenses for external code sources are included inline in the source code itself.
## Searching for a model
To see the configuration options, run `python3 train_search.py --help` from the directory `cnn`. The code is also commented.
+### Scalar Search
+
+Here is how to do a search configured to find a model like SharpSepConvDARTS:
+
+```
+export CUDA_VISIBLE_DEVICES="0" && python3 train_search.py --dataset cifar10 --batch_size 48 --layers_of_cells 8 --layers_in_cells 4 --save scalar_SharpSepConvDARTS_SEARCH_`git rev-parse --short HEAD` --init_channels 16 --epochs 120 --cutout --autoaugment --seed 22 --weighting_algorithm scalar --primitives DARTS_PRIMITIVES
+```
+
+### Max-W Regularization Search
+
+
+export CUDA_VISIBLE_DEVICES="0" && python3 train_search.py --dataset cifar10 --batch_size 48 --layers_of_cells 8 --layers_in_cells 4 --save max_w_SharpSepConvDARTS_SEARCH_`git rev-parse --short HEAD` --init_channels 16 --epochs 120 --cutout --autoaugment --seed 22 --weighting_algorithm max_w --primitives DARTS_PRIMITIVES
Run `cnn/train_search.py` with your configuration. Place the best genotype into `genotypes.py`, preferably with a record of the raw weights as well and other command execution data so similar results can be reproduced in the future.
+### Visualization
+
+Here are examples of how to visualize the cell structures from a genotype definition found int `genotypes.py`:
+```
+cd cnn
+
+python3 visualize.py SHARPSEPCONV_DARTS
+python3 visualize.py SHARP_DARTS
+python3 visualize.py DARTS
+```
+
## Training a final Model
To see the configuration options, run `python3 train.py --help` from the directory `cnn`. The code is also commented.
### CIFAR-10 Training
-Best Results with SharpSepConvDARTS:
+To reproduce the SharpSepConvDARTS results with 1.93% (1.98+/-0.07) validation error on CIFAR-10 and 5.5% error (5.8+/-0.3) on the CIFAR-10.1 test set:
+
```
export CUDA_VISIBLE_DEVICES="0" && python3 train.py --autoaugment --auxiliary --cutout --batch_size 64 --epochs 2000 --save SHARPSEPCONV_DARTS_2k_`git rev-parse --short HEAD`_cospower_min_1e-8 --arch SHARPSEPCONV_DARTS --learning_rate 0.025 --learning_rate_min 1e-8 --cutout_length 16 --init_channels 36 --dataset cifar10
```
@@ -48,7 +68,7 @@ Collecting multiple data points:
for i in {1..8}; do export CUDA_VISIBLE_DEVICES="0" && python3 train.py --autoaugment --auxiliary --cutout --batch_size 64 --epochs 2000 --save SHARPSEPCONV_DARTS_MAX_W_2k_`git rev-parse --short HEAD`_cospower_min_1e-8 --learning_rate 0.025 --learning_rate_min 1e-8 --cutout_length 16 --init_channels 36 --dataset cifar10 --arch SHARPSEPCONV_DARTS_MAX_W ; done;
```
-Collecting results from multiple runs into a file from `sharperDARTS/cnn` directory with [ack-grep](https://beyondgrep.com/) (on some machiens it is just `ack`):
+Collecting results from multiple runs into a file from `sharperDARTS/cnn` directory with [ack-grep](https://beyondgrep.com/) (on some machines the command is just `ack`):
```
ack-grep --match "cifar10.1" */*.txt > cifar10.1_results_femur.txt
```
@@ -60,7 +80,7 @@ These configurations are designed for an NVIDIA RTX 1080Ti, `--fp16` should be r
You'll need to first [acquire the imagenet files](http://image-net.org/download) and preprocess them.
-Best SharpSepConvDARTS Results:
+Training a SharpSepConvDARTS model on ImageNet where we expect approximately 25.1% top-1 (7.8% top-5) error:
```
python3 -m torch.distributed.launch --nproc_per_node=2 main_fp16_optimizer.py --fp16 --b 224 --save `git rev-parse --short HEAD`_DARTS_PRIMITIVES_DIL_IS_SEPCONV --epochs 300 --dynamic-loss-scale --workers 20 --autoaugment --auxiliary --cutout --data /home/costar/datasets/imagenet/ --learning_rate 0.05 --learning_rate_min 0.00075 --arch DARTS_PRIMITIVES_DIL_IS_SEPCONV
@@ -154,9 +174,10 @@ Here is the key line with the settings you'll want to use:
lr_schedule is a numpy array containing the learning rate at each epoch.
-# sharpDARTS Repository based on Differentiable Architecture Search (DARTS)
+## The sharpDARTS Repository is based on Differentiable Architecture Search (DARTS)
+
+The following is a lightly edited and updated reproduction of the README.md from the original [DARTS Code](https://github.com/quark0/darts/tree/f276dd346a09ae3160f8e3aca5c7b193fda1da37) accompanying the paper [DARTS: Differentiable Architecture Search](https://arxiv.org/abs/1806.09055):
-Code accompanying the paper
> [DARTS: Differentiable Architecture Search](https://arxiv.org/abs/1806.09055)\
> Hanxiao Liu, Karen Simonyan, Yiming Yang.\
> _arXiv:1806.09055_.
@@ -164,18 +185,18 @@ Code accompanying the paper
+
The algorithm is based on continuous relaxation and gradient descent in the architecture space. It is able to efficiently design high-performance convolutional architectures for image classification (on CIFAR-10 and ImageNet) and recurrent architectures for language modeling (on Penn Treebank and WikiText-2). Only a single GPU is required.
-## Requirements
+### Requirements
```
Python >= 3.5.5, PyTorch == 0.3.1, torchvision == 0.2.0
```
-NOTE: PyTorch 0.4 is not supported at this moment and would lead to OOM.
-## Datasets
+### Datasets
Instructions for acquiring PTB and WT2 can be found [here](https://github.com/salesforce/awd-lstm-lm). While CIFAR-10 can be automatically downloaded by torchvision, ImageNet needs to be manually downloaded (preferably to a SSD) following the instructions [here](https://github.com/pytorch/examples/tree/master/imagenet).
-## Pretrained models
+### Pretrained models
The easist way to get started is to evaluate our pretrained DARTS models.
**CIFAR-10** ([cifar10_model.pt](https://drive.google.com/file/d/1Y13i4zKGKgjtWBdC0HWLavjO7wvEiGOc/view?usp=sharing))
@@ -196,7 +217,7 @@ cd cnn && python test_imagenet.py --auxiliary --model_path imagenet_model.pt
```
* Expected result: 26.7% top-1 error and 8.7% top-5 error with 4.7M model params.
-## Architecture search (using small proxy models)
+### Architecture search (using small proxy models)
To carry out architecture search using 2nd-order approximation, run
```
cd cnn && python train_search.py --unrolled # for conv cells on CIFAR-10
@@ -215,7 +236,7 @@ Also be aware that different runs would end up with different local minimum. To
Figure: Snapshots of the most likely normal conv, reduction conv, and recurrent cells over time.
-## Architecture evaluation (using full-sized models)
+### Architecture evaluation (using full-sized models)
To evaluate our best cells by training from scratch, run
```
cd cnn && python train.py --auxiliary --cutout # CIFAR-10
@@ -237,20 +258,43 @@ The CIFAR-10 result at the end of training is subject to variance due to the non
Figure: Expected learning curves on CIFAR-10 (4 runs), ImageNet and PTB.
-## Visualization
+### Visualization
Package [graphviz](https://graphviz.readthedocs.io/en/stable/index.html) is required to visualize the learned cells
```
python visualize.py DARTS
```
where `DARTS` can be replaced by any customized architectures in `genotypes.py`.
-## Citation
-If you use any part of this code in your research, please cite our [paper](https://arxiv.org/abs/1806.09055):
+## Citations
+
+Please cite sharpDARTS if you use the sharpDARTS code as part of your research! By using any part of the code you are agreeing to comply with our permissive Apache 2.0 license.
+
+```
+@article{hundt2019sharpdarts,
+ author = {Andrew Hundt and
+ Varun Jain and
+ Gregory D. Hager},
+ title = {sharpDARTS: Faster and More Accurate Differentiable Architecture Search},
+ journal = {CoRR},
+ volume = {abs/1903.09900},
+ year = {2019},
+ url = {http://arxiv.org/abs/1903.09900},
+ archivePrefix = {arXiv},
+ eprint = {1903.09900},
+ biburl = {https://dblp.org/rec/bib/journals/corr/abs-1903-09900},
+ bibsource = {dblp computer science bibliography, https://dblp.org}
+}
+```
+
+If you use any part of the DARTS code in your research, please cite [DARTS: Differentiable Architecture Search](https://arxiv.org/abs/1806.09055):
+
```
-@article{liu2018darts,
- title={DARTS: Differentiable Architecture Search},
- author={Liu, Hanxiao and Simonyan, Karen and Yang, Yiming},
- journal={arXiv preprint arXiv:1806.09055},
- year={2018}
+@inproceedings{
+ liu2018darts,
+ title={{DARTS}: {D}ifferentiable {A}rchitecture {S}earch},
+ author={Hanxiao Liu and Karen Simonyan and Yiming Yang},
+ booktitle={International Conference on Learning Representations},
+ year={2019},
+ url={https://openreview.net/forum?id=S1eYHoC5FX},
}
```
From dc4058042f0601879e4cfe6e44f24ccdac039fd8 Mon Sep 17 00:00:00 2001
From: Andrew Hundt
Date: Thu, 30 May 2019 17:21:28 -0400
Subject: [PATCH 30/40] README.md add images
---
README.md | 6 +
img/cos_power_annealing_imagenet.png | Bin 0 -> 211605 bytes
img/multi_channel_net_2x2_x2x2x2.svg | 743 +++++++++++++++++++++++++++
3 files changed, 749 insertions(+)
create mode 100644 img/cos_power_annealing_imagenet.png
create mode 100644 img/multi_channel_net_2x2_x2x2x2.svg
diff --git a/README.md b/README.md
index fb37f03..19d2610 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# sharpDARTS: Faster, More Accurate Differentiable Architecture Search
+![Differentiable Hyperparameter Search Example Graph](img/multi_channel_net_2x2_x2x2x2.svg)
+
Please cite [sharpDARTS: Faster, More Accurate Differentiable Architecture Search](http://arxiv.org/abs/1903.09900) if you use this code as part of your research! By using any part of the code you are agreeing to comply with our permissive Apache 2.0 license.
```
@@ -101,6 +103,8 @@ export CUDA_VISIBLE_DEVICES="0" && python3 main_fp16_optimizer.py --fp16 --b 256
## Differentiable Hyperparameter Search on CIFAR-10
+![Differentiable Hyperparameter Search Example Graph](img/multi_channel_net_2x2_x2x2x2.svg)
+
Searching for a Model:
```
export CUDA_VISIBLE_DEVICES="1" && python2 train_search.py --dataset cifar10 --batch_size 64 --save MULTI_CHANNEL_SEARCH_`git rev-parse --short HEAD`_search_weighting_max_w --init_channels 36 --epochs 120 --cutout --autoaugment --seed 10 --weighting_algorithm max_w --multi_channel
@@ -115,6 +119,8 @@ for i in {1..5}; do export CUDA_VISIBLE_DEVICES="0" && python3 train.py --b 512
## Cosine Power Annealing
+![Cosine Power Annealing Example Curve](img/cos_power_annealing_imagenet.png)
+
Cosine Power annealing is designed to be a learning rate schedule which improves on cosine annealing.
See `consine_power_annealing.py` for the code, and `cnn/train.py` for an example of using the API.
diff --git a/img/cos_power_annealing_imagenet.png b/img/cos_power_annealing_imagenet.png
new file mode 100644
index 0000000000000000000000000000000000000000..b964ef41a616675e89aecd0bb24a5de3804afba4
GIT binary patch
literal 211605
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