blob: 7011143acf64dad53b195874a47d2bd5b7e501d3 [file] [log] [blame]
// Copyright 2014 Google Inc. All Rights Reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Author: nevena@google.com (Nevena Lazic)
#include "lossmin/losses/inner-product-loss-function.h"
#include <math.h>
namespace lossmin {
double InnerProductLossFunction::LossCurvature(
const InstanceSet &instances) const {
double data_curvature = (instances.cwiseProduct(instances) *
Weights::Ones(instances.cols())).maxCoeff();
return curvature_ * data_curvature;
}
void InnerProductLossFunction::PerCoordinateCurvature(
const InstanceSet &instances, VectorXd *per_coordinate_curvature) const {
*per_coordinate_curvature =
VectorXd::Ones(instances.rows()).transpose() *
instances.cwiseProduct(instances) / instances.rows();
*per_coordinate_curvature *= curvature_;
}
double InnerProductLossFunction::ExampleLoss(
const Weights &weights, const InstanceSet &instances,
const LabelSet &labels, int example) const {
double inner_product = instances.innerVector(example).dot(weights);
return InnerProductExampleLoss(inner_product, labels.coeff(example, 0));
}
void InnerProductLossFunction::AddExampleGradient(
const Weights &weights, const InstanceSet &instances,
const LabelSet &labels, int example, double weights_scale,
double example_scale, Weights *gradient) const {
double inner_product = instances.innerVector(example).dot(weights);
if (weights_scale != 1.0) inner_product *= weights_scale;
double inner_product_gradient =
InnerProductExampleGradient(inner_product, labels.coeff(example, 0));
if (example_scale != 1.0) inner_product_gradient *= example_scale;
if (synchronous_update()) {
std::lock_guard<std::mutex> lock(gradient_update_mutex_);
for (InstanceSet::InnerIterator it(instances, example); it; ++it) {
gradient->coeffRef(it.index()) += inner_product_gradient * it.value();
}
} else {
for (InstanceSet::InnerIterator it(instances, example); it; ++it) {
gradient->coeffRef(it.index()) += inner_product_gradient * it.value();
}
}
}
void InnerProductLossFunction::ExampleGradient(
const Weights &weights, const InstanceSet &instances,
const LabelSet &labels, int example, double weights_scale,
double example_scale,
std::vector<std::pair<int, double>> *example_gradient) const {
double inner_product = instances.innerVector(example).dot(weights);
if (weights_scale != 1.0) inner_product *= weights_scale;
double inner_product_gradient =
InnerProductExampleGradient(inner_product, labels.coeff(example, 0));
if (example_scale != 1.0) inner_product_gradient *= example_scale;
example_gradient->resize(instances.row(example).nonZeros());
int i = 0;
for (InstanceSet::InnerIterator it(instances, example); it; ++it) {
example_gradient->at(i++) =
std::make_pair(it.index(), inner_product_gradient * it.value());
}
}
// Assigns labels to 'instances' given 'weights'.
void InnerProductLossFunction::PredictLabels(
const Weights &weights, const InstanceSet &instances,
LabelSet *labels) const {
// Compute inner products.
VectorXd inner_products = instances * weights;
// Assign labels by calling InnerProductAssignLabel coefficientwise on
// 'inner_products'.
std::function<double(double)> assign_label_ptr =
std::bind(&InnerProductLossFunction::InnerProductPredictLabel,
this, std::placeholders::_1);
*labels = inner_products.unaryExpr(assign_label_ptr);
}
} // namespace lossmin