def save_files_classification(self):
        """
        Save solver, train_val and deploy files to disk
        """
        network = cleanedUpClassificationNetwork(self.network, len(self.get_labels()))
        data_layers, train_val_layers, deploy_layers = filterLayersByState(network)

        ### Write train_val file

        train_val_network = caffe_pb2.NetParameter()

        # Data layers
        # TODO clean this up

        train_data_layer = None
        val_data_layer = None

        for layer in data_layers.layer:
            for rule in layer.include:
                if rule.phase == caffe_pb2.TRAIN:
                    assert train_data_layer is None, 'cannot specify two train data layers'
                    train_data_layer = layer
                elif rule.phase == caffe_pb2.TEST:
                    assert val_data_layer is None, 'cannot specify two test data layers'
                    val_data_layer = layer

        if train_data_layer is None:
            assert val_data_layer is None, 'cannot specify a test data layer without a train data layer'

        dataset_backend = self.dataset.train_db_task().backend
        has_val_set = self.dataset.val_db_task() is not None

        if train_data_layer is not None:
            if dataset_backend == 'lmdb':
                assert train_data_layer.type == 'Data', 'expecting a Data layer'
            elif dataset_backend == 'hdf5':
                assert train_data_layer.type == 'HDF5Data', 'expecting an HDF5Data layer'
            if dataset_backend == 'lmdb' and train_data_layer.HasField('data_param'):
                assert not train_data_layer.data_param.HasField('source'), "don't set the data_param.source"
                assert not train_data_layer.data_param.HasField('backend'), "don't set the data_param.backend"
            if dataset_backend == 'hdf5' and train_data_layer.HasField('hdf5_data_param'):
                assert not train_data_layer.hdf5_data_param.HasField('source'), "don't set the hdf5_data_param.source"
            max_crop_size = min(self.dataset.image_dims[0], self.dataset.image_dims[1])
            if self.crop_size:
                assert dataset_backend != 'hdf5', 'HDF5Data layer does not support cropping'
                assert self.crop_size <= max_crop_size, 'crop_size is larger than the image size'
                train_data_layer.transform_param.crop_size = self.crop_size
            elif train_data_layer.transform_param.HasField('crop_size'):
                cs = train_data_layer.transform_param.crop_size
                if cs > max_crop_size:
                    # don't throw an error here
                    cs = max_crop_size
                train_data_layer.transform_param.crop_size = cs
                self.crop_size = cs
            train_val_network.layer.add().CopyFrom(train_data_layer)
            train_data_layer = train_val_network.layer[-1]
            if val_data_layer is not None and has_val_set:
                if dataset_backend == 'lmdb':
                    assert val_data_layer.type == 'Data', 'expecting a Data layer'
                elif dataset_backend == 'hdf5':
                    assert val_data_layer.type == 'HDF5Data', 'expecting an HDF5Data layer'
                if dataset_backend == 'lmdb' and val_data_layer.HasField('data_param'):
                    assert not val_data_layer.data_param.HasField('source'), "don't set the data_param.source"
                    assert not val_data_layer.data_param.HasField('backend'), "don't set the data_param.backend"
                if dataset_backend == 'hdf5' and val_data_layer.HasField('hdf5_data_param'):
                    assert not val_data_layer.hdf5_data_param.HasField('source'), "don't set the hdf5_data_param.source"
                if self.crop_size:
                    # use our error checking from the train layer
                    val_data_layer.transform_param.crop_size = self.crop_size
                train_val_network.layer.add().CopyFrom(val_data_layer)
                val_data_layer = train_val_network.layer[-1]
        else:
            layer_type = 'Data'
            if dataset_backend == 'hdf5':
                layer_type = 'HDF5Data'
            train_data_layer = train_val_network.layer.add(type = layer_type, name = 'data')
            train_data_layer.top.append('data')
            train_data_layer.top.append('label')
            train_data_layer.include.add(phase = caffe_pb2.TRAIN)
            if dataset_backend == 'lmdb':
                train_data_layer.data_param.batch_size = constants.DEFAULT_BATCH_SIZE
            elif dataset_backend == 'hdf5':
                train_data_layer.hdf5_data_param.batch_size = constants.DEFAULT_BATCH_SIZE
            if self.crop_size:
                assert dataset_backend != 'hdf5', 'HDF5Data layer does not support cropping'
                train_data_layer.transform_param.crop_size = self.crop_size
            if has_val_set:
                val_data_layer = train_val_network.layer.add(type = layer_type, name = 'data')
                val_data_layer.top.append('data')
                val_data_layer.top.append('label')
                val_data_layer.include.add(phase = caffe_pb2.TEST)
                if dataset_backend == 'lmdb':
                    val_data_layer.data_param.batch_size = constants.DEFAULT_BATCH_SIZE
                elif dataset_backend == 'hdf5':
                    val_data_layer.hdf5_data_param.batch_size = constants.DEFAULT_BATCH_SIZE
                if self.crop_size:
                    val_data_layer.transform_param.crop_size = self.crop_size
        if dataset_backend == 'lmdb':
            train_data_layer.data_param.source = self.dataset.path(self.dataset.train_db_task().db_name)
            train_data_layer.data_param.backend = caffe_pb2.DataParameter.LMDB
            if val_data_layer is not None and has_val_set:
                val_data_layer.data_param.source = self.dataset.path(self.dataset.val_db_task().db_name)
                val_data_layer.data_param.backend = caffe_pb2.DataParameter.LMDB
        elif dataset_backend == 'hdf5':
            train_data_layer.hdf5_data_param.source = self.dataset.path(self.dataset.train_db_task().textfile)
            if val_data_layer is not None and has_val_set:
                val_data_layer.hdf5_data_param.source = self.dataset.path(self.dataset.val_db_task().textfile)

        if self.use_mean == 'pixel':
            assert dataset_backend != 'hdf5', 'HDF5Data layer does not support mean subtraction'
            mean_pixel = self.get_mean_pixel(self.dataset.path(self.dataset.train_db_task().mean_file))
            self.set_mean_value(train_data_layer, mean_pixel)
            if val_data_layer is not None and has_val_set:
                self.set_mean_value(val_data_layer, mean_pixel)

        elif self.use_mean == 'image':
            self.set_mean_file(train_data_layer, self.dataset.path(self.dataset.train_db_task().mean_file))
            if val_data_layer is not None and has_val_set:
                self.set_mean_file(val_data_layer, self.dataset.path(self.dataset.train_db_task().mean_file))

        if self.batch_size:
            if dataset_backend == 'lmdb':
                train_data_layer.data_param.batch_size = self.batch_size
                if val_data_layer is not None and has_val_set:
                    val_data_layer.data_param.batch_size = self.batch_size
            elif dataset_backend == 'hdf5':
                train_data_layer.hdf5_data_param.batch_size = self.batch_size
                if val_data_layer is not None and has_val_set:
                    val_data_layer.hdf5_data_param.batch_size = self.batch_size
        else:
            if dataset_backend == 'lmdb':
                if not train_data_layer.data_param.HasField('batch_size'):
                    train_data_layer.data_param.batch_size = constants.DEFAULT_BATCH_SIZE
                if val_data_layer is not None and has_val_set and not val_data_layer.data_param.HasField('batch_size'):
                    val_data_layer.data_param.batch_size = constants.DEFAULT_BATCH_SIZE
            elif dataset_backend == 'hdf5':
                if not train_data_layer.hdf5_data_param.HasField('batch_size'):
                    train_data_layer.hdf5_data_param.batch_size = constants.DEFAULT_BATCH_SIZE
                if val_data_layer is not None and has_val_set and not val_data_layer.hdf5_data_param.HasField('batch_size'):
                    val_data_layer.hdf5_data_param.batch_size = constants.DEFAULT_BATCH_SIZE

        # Non-data layers
        train_val_network.MergeFrom(train_val_layers)

        # Write to file
        with open(self.path(self.train_val_file), 'w') as outfile:
            text_format.PrintMessage(train_val_network, outfile)

        # network sanity checks
        self.logger.debug("Network sanity check - train")
        CaffeTrainTask.net_sanity_check(train_val_network, caffe_pb2.TRAIN)
        if has_val_set:
            self.logger.debug("Network sanity check - val")
            CaffeTrainTask.net_sanity_check(train_val_network, caffe_pb2.TEST)

        ### Write deploy file

        deploy_network = caffe_pb2.NetParameter()

        # Input
        deploy_network.input.append('data')
        shape = deploy_network.input_shape.add()
        shape.dim.append(1)
        shape.dim.append(self.dataset.image_dims[2])
        if self.crop_size:
            shape.dim.append(self.crop_size)
            shape.dim.append(self.crop_size)
        else:
            shape.dim.append(self.dataset.image_dims[0])
            shape.dim.append(self.dataset.image_dims[1])

        # Layers
        deploy_network.MergeFrom(deploy_layers)

        # Write to file
        with open(self.path(self.deploy_file), 'w') as outfile:
            text_format.PrintMessage(deploy_network, outfile)

        # network sanity checks
        self.logger.debug("Network sanity check - deploy")
        CaffeTrainTask.net_sanity_check(deploy_network, caffe_pb2.TEST)
        found_softmax = False
        for layer in deploy_network.layer:
            if layer.type == 'Softmax':
                found_softmax = True
                break
        assert found_softmax, 'Your deploy network is missing a Softmax layer! Read the documentation for custom networks and/or look at the standard networks for examples.'

        ### Write solver file

        solver = caffe_pb2.SolverParameter()
        # get enum value for solver type
        solver.solver_type = getattr(solver, self.solver_type)
        solver.net = self.train_val_file

        # Set CPU/GPU mode
        if config_value('caffe_root')['cuda_enabled'] and \
                bool(config_value('gpu_list')):
            solver.solver_mode = caffe_pb2.SolverParameter.GPU
        else:
            solver.solver_mode = caffe_pb2.SolverParameter.CPU

        solver.snapshot_prefix = self.snapshot_prefix

        # Epochs -> Iterations
        train_iter = int(math.ceil(float(self.dataset.train_db_task().entries_count) / train_data_layer.data_param.batch_size))
        solver.max_iter = train_iter * self.train_epochs
        snapshot_interval = self.snapshot_interval * train_iter
        if 0 < snapshot_interval <= 1:
            solver.snapshot = 1 # don't round down
        elif 1 < snapshot_interval < solver.max_iter:
            solver.snapshot = int(snapshot_interval)
        else:
            solver.snapshot = 0 # only take one snapshot at the end

        if has_val_set and self.val_interval:
            solver.test_iter.append(int(math.ceil(float(self.dataset.val_db_task().entries_count) / val_data_layer.data_param.batch_size)))
            val_interval = self.val_interval * train_iter
            if 0 < val_interval <= 1:
                solver.test_interval = 1 # don't round down
            elif 1 < val_interval < solver.max_iter:
                solver.test_interval = int(val_interval)
            else:
                solver.test_interval = solver.max_iter # only test once at the end

        # Learning rate
        solver.base_lr = self.learning_rate
        solver.lr_policy = self.lr_policy['policy']
        scale = float(solver.max_iter)/100.0
        if solver.lr_policy == 'fixed':
            pass
        elif solver.lr_policy == 'step':
            # stepsize = stepsize * scale
            solver.stepsize = int(math.ceil(float(self.lr_policy['stepsize']) * scale))
            solver.gamma = self.lr_policy['gamma']
        elif solver.lr_policy == 'multistep':
            for value in self.lr_policy['stepvalue'].split(','):
                # stepvalue = stepvalue * scale
                solver.stepvalue.append(int(math.ceil(float(value) * scale)))
            solver.gamma = self.lr_policy['gamma']
        elif solver.lr_policy == 'exp':
            # gamma = gamma^(1/scale)
            solver.gamma = math.pow(self.lr_policy['gamma'], 1.0/scale)
        elif solver.lr_policy == 'inv':
            # gamma = gamma / scale
            solver.gamma = self.lr_policy['gamma'] / scale
            solver.power = self.lr_policy['power']
        elif solver.lr_policy == 'poly':
            solver.power = self.lr_policy['power']
        elif solver.lr_policy == 'sigmoid':
            # gamma = -gamma / scale
            solver.gamma = -1.0 * self.lr_policy['gamma'] / scale
            # stepsize = stepsize * scale
            solver.stepsize = int(math.ceil(float(self.lr_policy['stepsize']) * scale))
        else:
            raise Exception('Unknown lr_policy: "%s"' % solver.lr_policy)

        # These solver types don't support momentum
        unsupported = [solver.ADAGRAD]
        try:
            unsupported.append(solver.RMSPROP)
        except __HOLE__:
            pass

        # go with the suggested defaults
        if solver.solver_type not in unsupported:
            solver.momentum = 0.9
        solver.weight_decay = 0.0005

        # Display 8x per epoch, or once per 5000 images, whichever is more frequent
        solver.display = max(1, min(
                int(math.floor(float(solver.max_iter) / (self.train_epochs * 8))),
                int(math.ceil(5000.0 / train_data_layer.data_param.batch_size))
                ))

        if self.random_seed is not None:
            solver.random_seed = self.random_seed

        with open(self.path(self.solver_file), 'w') as outfile:
            text_format.PrintMessage(solver, outfile)
        self.solver = solver # save for later

        return True
dataset/ETHPy150Open NVIDIA/DIGITS/digits/model/tasks/caffe_train.py/CaffeTrainTask.save_files_classification