function model = train_models(config, file_info, feat_types)

model_name = ['complete_' config.model_params.model_type '_model.mat'];
model_dir = fullfile(config.paths.model_results, 'models', config.split_name);
complete_model_path = fullfile(model_dir, model_name);

if exist(complete_model_path, 'file')
    fprintf('Loading complete model from %s\n', complete_model_path);
    load(complete_model_path, 'model');
    return
end

if ~exist(model_dir, 'dir')
    mkdir(model_dir);
end

fprintf('Aggregating features for %s\n', complete_model_path);
[X, Y, seg_size, ~] = aggregate_features(config, file_info, feat_types);

if isfield(config.model_params, 'sparse_threshold')
    X(X < config.model_params.sparse_threshold) = 0;
end

model.class_name = config.data_info.labels;
model.params = config.model_params;
n_lab = length(model.class_name);

if model.params.center_data
    mu = mean(X,1);
    X = bsxfun(@minus, X, mu);
    model.mu = mu;
end

if model.params.unit_variance
    siginv = 1./(std(X,0,1) + eps);
    X = bsxfun(@times, X, siginv);
    model.siginv = siginv;
end

switch model.params.model_type
  case 'one-vs-all'
    model_name = [model.params.model_type '.mat'];
    model.params.path = fullfile(model_dir, model_name);
    model.svm = train_svm(model.params, X, Y);

  case 'binary'
    if size(Y, 2) == 1
        Y_inds = sub2ind([size(Y, 1) numel(unique(Y))], ...
                         [1:size(Y, 1)]', Y + 1);
        Y = zeros([size(Y, 1) numel(unique(Y))]);
        Y(Y_inds) = 1;
    else
        Y = double(Y == 1);
    end

    for ind = 1:n_lab
        model_name = [model.params.model_type '_' model.class_name{ind} '.mat'];
        model.params.path = fullfile(model_dir, model_name);
        model.svm(ind) = train_svm(model.params, X, Y(:, ind));
    end
  
  case 'rank'
    model.pair_inds = find(reshape(tril(ones(n_lab), -1), [1 n_lab^2]));
    pair_labels = bsxfun(@minus, repmat(Y, [1 1 n_lab]), permute(Y, [1 3 2]));
    pair_labels = sign(reshape(pair_labels, [size(Y, 1) n_lab^2]));
    pair_labels = pair_labels(:, model.pair_inds);
    valid_pairs = pair_labels ~= 0;
    pair_labels = max(pair_labels, 0);
    
    for ind = 1:size(pair_labels, 2)
        model_name = [model.params.model_type '_' num2str(ind) '.mat'];
        model.params.path = fullfile(model_dir, model_name);
        model.svm(ind) = train_svm(model.params, X(valid_pairs(:,ind)), ...
                                   pair_labels(valid_pairs(:,ind), ind));
    end
    
  otherwise
    error('unknown model type');
end

model.params.path = complete_model_path;
save(model.params.path, 'model');
fprintf('\n---Complete model written to %s---\n', complete_model_path);

end
