def save_files_generic(self):
        """
        Save solver, train_val and deploy files to disk
        """
        train_image_db = None
        train_labels_db = None
        val_image_db = None
        val_labels_db = None
        for task in self.dataset.tasks:
            if task.purpose == 'Training Images':
                train_image_db = task
            if task.purpose == 'Training Labels':
                train_labels_db = task
            if task.purpose == 'Validation Images':
                val_image_db = task
            if task.purpose == 'Validation Labels':
                val_labels_db = task

        assert train_image_db is not None, 'Training images are required'

        ### Split up train_val and deploy layers

        network = cleanedUpGenericNetwork(self.network)
        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_image_data_layer = None
        train_label_data_layer = None
        val_image_data_layer = None
        val_label_data_layer = None

        for layer in data_layers.layer:
            for rule in layer.include:
                if rule.phase == caffe_pb2.TRAIN:
                    if 'data' in layer.top:
                        assert train_image_data_layer is None, 'cannot specify two train image data layers'
                        train_image_data_layer = layer
                    elif 'label' in layer.top:
                        assert train_label_data_layer is None, 'cannot specify two train label data layers'
                        train_label_data_layer = layer
                elif rule.phase == caffe_pb2.TEST:
                    if 'data' in layer.top:
                        assert val_image_data_layer is None, 'cannot specify two val image data layers'
                        val_image_data_layer = layer
                    elif 'label' in layer.top:
                        assert val_label_data_layer is None, 'cannot specify two val label data layers'
                        val_label_data_layer = layer

        train_image_data_layer = self.make_generic_data_layer(train_image_db, train_image_data_layer, 'data', 'data', caffe_pb2.TRAIN)
        if train_image_data_layer is not None:
            train_val_network.layer.add().CopyFrom(train_image_data_layer)
        train_label_data_layer = self.make_generic_data_layer(train_labels_db, train_label_data_layer, 'label', 'label', caffe_pb2.TRAIN)
        if train_label_data_layer is not None:
            train_val_network.layer.add().CopyFrom(train_label_data_layer)

        val_image_data_layer = self.make_generic_data_layer(val_image_db, val_image_data_layer, 'data', 'data', caffe_pb2.TEST)
        if val_image_data_layer is not None:
            train_val_network.layer.add().CopyFrom(val_image_data_layer)
        val_label_data_layer = self.make_generic_data_layer(val_labels_db, val_label_data_layer, 'label', 'label', caffe_pb2.TEST)
        if val_label_data_layer is not None:
            train_val_network.layer.add().CopyFrom(val_label_data_layer)

        # 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)
        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(train_image_db.image_channels)
        if train_image_data_layer.transform_param.HasField('crop_size'):
            shape.dim.append(
                    train_image_data_layer.transform_param.crop_size)
            shape.dim.append(
                    train_image_data_layer.transform_param.crop_size)
        else:
            shape.dim.append(train_image_db.image_height)
            shape.dim.append(train_image_db.image_width)

        # 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)

        ### 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(train_image_db.image_count) / train_image_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 val_image_data_layer:
            solver.test_iter.append(int(math.ceil(float(val_image_db.image_count) / val_image_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_image_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_generic