Commit b3f0a775 authored by Jia's avatar Jia Committed by Commit Bot

[Power ML] Change smart dim model interface to return ModelPrediction.

Model could error out so we need to record this response in the log.
Also, the logged inactivity_score and decision_threshold are quantized
version of the actual values used in the inference. Hence the
model now returns it decision as part of the prediction.

Bug: 862461
Change-Id: I14c889d97bebd93b88a86027ff94b2ce7fad5bfb
Reviewed-on: https://chromium-review.googlesource.com/1154243
Commit-Queue: Jia Meng <jiameng@chromium.org>
Reviewed-by: default avatarSteven Holte <holte@chromium.org>
Reviewed-by: default avatarAndrew Moylan <amoylan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580740}
parent 804e7c9b
......@@ -17,16 +17,10 @@ class SmartDimModel {
public:
virtual ~SmartDimModel() = default;
// Returns whether an upcoming dim should go ahead based on input |features|.
// If |inactive_probability_out| and |threshold_out| are non-null, also
// returns model confidence (probability that user will remain inactive if
// screen is dimmed now) and threshold: if probability >= threshold then model
// will return true for this function. Both |inactive_probability_out| and
// |threshold_out| are expected to be in the range of [0, 1.0] so that they
// can be logged as model results.
virtual bool ShouldDim(const UserActivityEvent::Features& features,
float* inactive_probability_out,
float* threshold_out) = 0;
// Returns a prediction whether an upcoming dim should go ahead based on input
// |features|.
virtual UserActivityEvent::ModelPrediction ShouldDim(
const UserActivityEvent::Features& features) = 0;
};
} // namespace ml
......
......@@ -13,17 +13,14 @@ SmartDimModelImpl::SmartDimModelImpl() = default;
SmartDimModelImpl::~SmartDimModelImpl() = default;
// TODO(jiameng): add impl.
bool SmartDimModelImpl::ShouldDim(const UserActivityEvent::Features& features,
float* inactive_probability_out,
float* threshold_out) {
UserActivityEvent::ModelPrediction SmartDimModelImpl::ShouldDim(
const UserActivityEvent::Features& features) {
// Let dim go ahead before we have a model implementation in place.
if (inactive_probability_out) {
*inactive_probability_out = 1.0;
}
if (threshold_out) {
*threshold_out = 0.0;
}
return true;
UserActivityEvent::ModelPrediction prediction;
prediction.set_decision_threshold(0);
prediction.set_inactivity_score(100);
prediction.set_response(UserActivityEvent::ModelPrediction::DIM);
return prediction;
}
} // namespace ml
......
......@@ -20,9 +20,8 @@ class SmartDimModelImpl : public SmartDimModel {
~SmartDimModelImpl() override;
// chromeos::power::ml::SmartDimModel overrides:
bool ShouldDim(const UserActivityEvent::Features& features,
float* inactive_probability_out,
float* threshold_out) override;
UserActivityEvent::ModelPrediction ShouldDim(
const UserActivityEvent::Features& features) override;
private:
DISALLOW_COPY_AND_ASSIGN(SmartDimModelImpl);
......
......@@ -179,14 +179,33 @@ message UserActivityEvent {
optional int32 previous_positive_actions_count = 30;
} // next id = 31
// All fields except |model_applied| in ModelPrediction are populated by the
// model. |model_applied| is populated by the UserActivityManager when
// deciding whether to apply the model decision.
message ModelPrediction {
// If |inactivity_score| < |decision_threshold| then dim will be deferred.
enum Response {
// Dim should go ahead.
DIM = 0;
// Dim should be deferred.
NO_DIM = 1;
// Model could fail to make a prediction due to various reasons, e.g. it
// could fail to load the preprocessor or process the features for
// inference.
MODEL_ERROR = 2;
}
// Both |inactivity_score| and |decision_threshold| are in the range of
// [0,100]. These values are the quantized versions of actual values used in
// making a model prediction, so that they can be logged later. If
// |inactivity_score| < |decision_threshold| then dim will be deferred.
optional int32 decision_threshold = 1;
// How likely user will remain inactive if screen is dimmed.
optional int32 inactivity_score = 2;
// Whether model decision (regardless if dim is to be deferred) is
// taken by powerd.
// taken by powerd. It is false if model response is MODEL_ERROR or if dim
// was deferred last time dim imminent occurred.
optional bool model_applied = 3;
optional Response response = 4;
}
optional ModelParams params = 1;
......
......@@ -193,30 +193,27 @@ void UserActivityManager::OnIdleEventObserved(
ExtractFeatures(activity_data);
if (base::FeatureList::IsEnabled(features::kUserActivityPrediction) &&
smart_dim_model_) {
float inactivity_probability = -1;
float threshold = -1;
const bool should_dim = smart_dim_model_->ShouldDim(
features_, &inactivity_probability, &threshold);
DCHECK(inactivity_probability >= 0 && inactivity_probability <= 1.0)
<< inactivity_probability;
DCHECK(threshold >= 0 && threshold <= 1.0) << threshold;
UserActivityEvent::ModelPrediction model_prediction;
// If previous dim was deferred, then model decision will not be applied
// to this event.
model_prediction.set_model_applied(!dim_deferred_);
model_prediction.set_decision_threshold(round(threshold * 100));
model_prediction.set_inactivity_score(round(inactivity_probability * 100));
model_prediction_ = model_prediction;
// Decide whether to defer the imminent screen dim.
UserActivityEvent::ModelPrediction model_prediction =
smart_dim_model_->ShouldDim(features_);
// Only defer the dim if the model predicts so and also if the dim was not
// previously deferred.
if (should_dim || dim_deferred_) {
dim_deferred_ = false;
} else {
if (model_prediction.response() ==
UserActivityEvent::ModelPrediction::NO_DIM &&
!dim_deferred_) {
power_manager_client_->DeferScreenDim();
dim_deferred_ = true;
model_prediction.set_model_applied(true);
} else {
// Either model predicts dim or model fails, or it was previously dimmed.
dim_deferred_ = false;
model_prediction.set_model_applied(
model_prediction.response() ==
UserActivityEvent::ModelPrediction::DIM &&
!dim_deferred_);
}
model_prediction_ = model_prediction;
}
waiting_for_final_action_ = true;
}
......
......@@ -156,9 +156,16 @@ void UserActivityUkmLoggerImpl::LogActivity(const UserActivityEvent& event) {
if (event.has_model_prediction()) {
const UserActivityEvent::ModelPrediction& model_prediction =
event.model_prediction();
user_activity.SetModelApplied(model_prediction.model_applied())
.SetModelDecisionThreshold(model_prediction.decision_threshold())
.SetModelInactivityScore(model_prediction.inactivity_score());
user_activity.SetModelResponse(model_prediction.response())
.SetModelApplied(model_prediction.model_applied());
if (model_prediction.response() ==
UserActivityEvent::ModelPrediction::DIM ||
model_prediction.response() ==
UserActivityEvent::ModelPrediction::NO_DIM) {
user_activity
.SetModelDecisionThreshold(model_prediction.decision_threshold())
.SetModelInactivityScore(model_prediction.inactivity_score());
}
}
user_activity.Record(ukm_recorder_);
......
......@@ -64,6 +64,7 @@ class UserActivityUkmLoggerTest : public testing::Test {
prediction->set_decision_threshold(50);
prediction->set_inactivity_score(60);
prediction->set_model_applied(true);
prediction->set_response(UserActivityEvent::ModelPrediction::NO_DIM);
user_activity_logger_delegate_ukm_.ukm_recorder_ = &recorder_;
}
......@@ -99,6 +100,7 @@ class UserActivityUkmLoggerTest : public testing::Test {
UserActivity::kModelDecisionThresholdName, 50);
recorder_.ExpectEntryMetric(entry, UserActivity::kModelInactivityScoreName,
60);
recorder_.ExpectEntryMetric(entry, UserActivity::kModelResponseName, 1);
recorder_.ExpectEntryMetric(entry, UserActivity::kMouseEventsInLastHourName,
89);
EXPECT_FALSE(recorder_.EntryHasMetric(entry, UserActivity::kOnBatteryName));
......@@ -238,6 +240,11 @@ TEST_F(UserActivityUkmLoggerTest, TwoUserActivityEvents) {
features->set_dim_to_screen_off_sec(20);
features->set_time_since_last_mouse_sec(200);
UserActivityEvent::ModelPrediction* prediction =
user_activity_event2.mutable_model_prediction();
prediction->set_model_applied(false);
prediction->set_response(UserActivityEvent::ModelPrediction::MODEL_ERROR);
LogActivity(user_activity_event_);
LogActivity(user_activity_event2);
......@@ -277,6 +284,12 @@ TEST_F(UserActivityUkmLoggerTest, TwoUserActivityEvents) {
recorder_.EntryHasMetric(entry1, UserActivity::kTimeSinceLastKeyName));
recorder_.ExpectEntryMetric(entry1, UserActivity::kTimeSinceLastMouseName,
200);
recorder_.ExpectEntryMetric(entry1, UserActivity::kModelResponseName, 2);
recorder_.ExpectEntryMetric(entry1, UserActivity::kModelAppliedName, 0);
EXPECT_FALSE(recorder_.EntryHasMetric(
entry1, UserActivity::kModelDecisionThresholdName));
EXPECT_FALSE(recorder_.EntryHasMetric(
entry1, UserActivity::kModelInactivityScoreName));
EXPECT_EQ(0u, recorder_.GetEntriesByName(UserActivityId::kEntryName).size());
}
......
......@@ -4212,6 +4212,12 @@ be describing additional metrics about the same event.
dim will be deferred.
</summary>
</metric>
<metric name="ModelResponse">
<summary>
Whether the model recommends the screen dim should be deferred (NO_DIM) or
allowed (DIM), or encountered an error (MODEL_ERROR).
</summary>
</metric>
<metric name="MouseEventsInLastHour">
<summary>
The number of mouse events reported as user activity in the last hour.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment