Author: srowen
Date: Tue Nov 22 06:48:38 2011
New Revision: 1204829
URL: http://svn.apache.org/viewvc?rev=1204829&view=rev
Log:
MAHOUT-891 add load statistics like average iteration time
Added:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java
mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java?rev=1204829&r1=1204828&r2=1204829&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java
Tue Nov 22 06:48:38 2011
@@ -158,7 +158,7 @@ public abstract class AbstractDifference
}
}
}
-
+
private float capEstimatedPreference(float estimate) {
if (estimate > maxPreference) {
return maxPreference;
@@ -168,7 +168,7 @@ public abstract class AbstractDifference
}
return estimate;
}
-
+
private double getEvaluation(FastByIDMap<PreferenceArray> testUserPrefs,
Recommender recommender)
throws TasteException {
reset();
@@ -179,14 +179,16 @@ public abstract class AbstractDifference
new PreferenceEstimateCallable(recommender, entry.getKey(),
entry.getValue(), noEstimateCounter));
}
log.info("Beginning evaluation of {} users", estimateCallables.size());
- execute(estimateCallables, noEstimateCounter);
+ RunningAverageAndStdDev timing = new FullRunningAverageAndStdDev();
+ execute(estimateCallables, noEstimateCounter, timing);
return computeFinalEvaluation();
}
- protected static void execute(Collection<Callable<Void>> callables,
AtomicInteger noEstimateCounter)
- throws TasteException {
+ protected static void execute(Collection<Callable<Void>> callables,
+ AtomicInteger noEstimateCounter,
+ RunningAverageAndStdDev timing) throws
TasteException {
- callables = wrapWithStatsCallables(callables, noEstimateCounter);
+ callables = wrapWithStatsCallables(callables, noEstimateCounter, timing);
int numProcessors = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(numProcessors);
log.info("Starting timing of {} tasks in {} threads", callables.size(),
numProcessors);
@@ -204,13 +206,13 @@ public abstract class AbstractDifference
executor.shutdown();
}
- private static Collection<Callable<Void>>
wrapWithStatsCallables(Collection<Callable<Void>> callables,
-
AtomicInteger noEstimateCounter) {
+ private static Collection<Callable<Void>>
wrapWithStatsCallables(Iterable<Callable<Void>> callables,
+
AtomicInteger noEstimateCounter,
+
RunningAverageAndStdDev timing) {
Collection<Callable<Void>> wrapped = Lists.newArrayList();
int count = 0;
- RunningAverageAndStdDev timing = new FullRunningAverageAndStdDev();
for (Callable<Void> callable : callables) {
- boolean logStats = count++ % 1000 == 0; // log every 100 or so iterations
+ boolean logStats = count++ % 1000 == 0; // log every 1000 or so
iterations
wrapped.add(new StatsCallable(callable, logStats, timing,
noEstimateCounter));
}
return wrapped;
@@ -221,14 +223,14 @@ public abstract class AbstractDifference
protected abstract void processOneEstimate(float estimatedPreference,
Preference realPref);
protected abstract double computeFinalEvaluation();
-
+
public final class PreferenceEstimateCallable implements Callable<Void> {
-
+
private final Recommender recommender;
private final long testUserID;
private final PreferenceArray prefs;
private final AtomicInteger noEstimateCounter;
-
+
public PreferenceEstimateCallable(Recommender recommender,
long testUserID,
PreferenceArray prefs,
@@ -238,7 +240,7 @@ public abstract class AbstractDifference
this.prefs = prefs;
this.noEstimateCounter = noEstimateCounter;
}
-
+
@Override
public Void call() throws TasteException {
for (Preference realPref : prefs) {
@@ -261,43 +263,7 @@ public abstract class AbstractDifference
}
return null;
}
-
- }
-
- private static final class StatsCallable implements Callable<Void> {
-
- private final Callable<Void> delegate;
- private final boolean logStats;
- private final RunningAverageAndStdDev timing;
- private final AtomicInteger noEstimateCounter;
-
- private StatsCallable(Callable<Void> delegate,
- boolean logStats,
- RunningAverageAndStdDev timing,
- AtomicInteger noEstimateCounter) {
- this.delegate = delegate;
- this.logStats = logStats;
- this.timing = timing;
- this.noEstimateCounter = noEstimateCounter;
- }
-
- @Override
- public Void call() throws Exception {
- long start = System.currentTimeMillis();
- delegate.call();
- long end = System.currentTimeMillis();
- timing.addDatum(end - start);
- if (logStats) {
- Runtime runtime = Runtime.getRuntime();
- int average = (int) timing.getAverage();
- log.info("Average time per recommendation: {}ms", average);
- long totalMemory = runtime.totalMemory();
- long memory = totalMemory - runtime.freeMemory();
- log.info("Approximate memory used: {}MB / {}MB", memory / 1000000L,
totalMemory / 1000000L);
- log.info("Unable to recommend in {} cases", noEstimateCounter.get());
- }
- return null;
- }
+
}
-
+
}
Added:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java?rev=1204829&view=auto
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java
(added)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java
Tue Nov 22 06:48:38 2011
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.cf.taste.impl.eval;
+
+import org.apache.mahout.cf.taste.recommender.Recommender;
+
+import java.util.concurrent.Callable;
+
+final class LoadCallable implements Callable<Void> {
+
+ private final Recommender recommender;
+ private final long userID;
+
+ LoadCallable(Recommender recommender, long userID) {
+ this.recommender = recommender;
+ this.userID = userID;
+ }
+
+ @Override
+ public Void call() throws Exception {
+ recommender.recommend(userID, 10);
+ return null;
+ }
+
+}
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java?rev=1204829&r1=1204828&r2=1204829&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java
Tue Nov 22 06:48:38 2011
@@ -23,7 +23,9 @@ import java.util.concurrent.atomic.Atomi
import com.google.common.collect.Lists;
import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.impl.common.FullRunningAverageAndStdDev;
import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
+import org.apache.mahout.cf.taste.impl.common.RunningAverageAndStdDev;
import org.apache.mahout.cf.taste.impl.common.SamplingLongPrimitiveIterator;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.recommender.Recommender;
@@ -34,36 +36,26 @@ import org.apache.mahout.cf.taste.recomm
public final class LoadEvaluator {
private LoadEvaluator() { }
+
+ public static LoadStatistics runLoad(Recommender recommender) throws
TasteException {
+ return runLoad(recommender, 10);
+ }
- public static void runLoad(Recommender recommender) throws TasteException {
+ public static LoadStatistics runLoad(Recommender recommender, int howMany)
throws TasteException {
DataModel dataModel = recommender.getDataModel();
int numUsers = dataModel.getNumUsers();
double sampleRate = 1000.0 / numUsers;
- LongPrimitiveIterator userSampler =
SamplingLongPrimitiveIterator.maybeWrapIterator(dataModel
- .getUserIDs(), sampleRate);
- recommender.recommend(userSampler.next(), 10); // Warm up
+ LongPrimitiveIterator userSampler =
+
SamplingLongPrimitiveIterator.maybeWrapIterator(dataModel.getUserIDs(),
sampleRate);
+ recommender.recommend(userSampler.next(), howMany); // Warm up
Collection<Callable<Void>> callables = Lists.newArrayList();
while (userSampler.hasNext()) {
callables.add(new LoadCallable(recommender, userSampler.next()));
}
- AbstractDifferenceRecommenderEvaluator.execute(callables, new
AtomicInteger());
- }
-
- private static final class LoadCallable implements Callable<Void> {
-
- private final Recommender recommender;
- private final long userID;
-
- private LoadCallable(Recommender recommender, long userID) {
- this.recommender = recommender;
- this.userID = userID;
- }
-
- @Override
- public Void call() throws Exception {
- recommender.recommend(userID, 10);
- return null;
- }
+ AtomicInteger noEstimateCounter = new AtomicInteger();
+ RunningAverageAndStdDev timing = new FullRunningAverageAndStdDev();
+ AbstractDifferenceRecommenderEvaluator.execute(callables,
noEstimateCounter, timing);
+ return new LoadStatistics(timing);
}
-
+
}
\ No newline at end of file
Added:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java?rev=1204829&view=auto
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java
(added)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java
Tue Nov 22 06:48:38 2011
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.cf.taste.impl.eval;
+
+import org.apache.mahout.cf.taste.impl.common.RunningAverage;
+
+public final class LoadStatistics {
+
+ private final RunningAverage timing;
+
+ LoadStatistics(RunningAverage timing) {
+ this.timing = timing;
+ }
+
+ public RunningAverage getTiming() {
+ return timing;
+ }
+
+}
Added:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java?rev=1204829&view=auto
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java
(added)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java
Tue Nov 22 06:48:38 2011
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.cf.taste.impl.eval;
+
+import org.apache.mahout.cf.taste.impl.common.RunningAverageAndStdDev;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicInteger;
+
+final class StatsCallable implements Callable<Void> {
+
+ private static final Logger log =
LoggerFactory.getLogger(StatsCallable.class);
+
+ private final Callable<Void> delegate;
+ private final boolean logStats;
+ private final RunningAverageAndStdDev timing;
+ private final AtomicInteger noEstimateCounter;
+
+ StatsCallable(Callable<Void> delegate,
+ boolean logStats,
+ RunningAverageAndStdDev timing,
+ AtomicInteger noEstimateCounter) {
+ this.delegate = delegate;
+ this.logStats = logStats;
+ this.timing = timing;
+ this.noEstimateCounter = noEstimateCounter;
+ }
+
+ @Override
+ public Void call() throws Exception {
+ long start = System.currentTimeMillis();
+ delegate.call();
+ long end = System.currentTimeMillis();
+ timing.addDatum(end - start);
+ if (logStats) {
+ Runtime runtime = Runtime.getRuntime();
+ int average = (int) timing.getAverage();
+ log.info("Average time per recommendation: {}ms", average);
+ long totalMemory = runtime.totalMemory();
+ long memory = totalMemory - runtime.freeMemory();
+ log.info("Approximate memory used: {}MB / {}MB", memory / 1000000L,
totalMemory / 1000000L);
+ log.info("Unable to recommend in {} cases", noEstimateCounter.get());
+ }
+ return null;
+ }
+
+}
Modified:
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java?rev=1204829&r1=1204828&r2=1204829&view=diff
==============================================================================
---
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java
(original)
+++
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java
Tue Nov 22 06:48:38 2011
@@ -1,5 +1,21 @@
-package org.apache.mahout.cf.taste.impl.eval;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.mahout.cf.taste.impl.eval;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
@@ -14,26 +30,37 @@ import org.apache.mahout.cf.taste.simila
import java.io.File;
-/**
- *
- *
- **/
-public class LoadEvaluationRunner {
+public final class LoadEvaluationRunner {
+
+ private static final int LOOPS = 10;
+
+ private LoadEvaluationRunner() {
+ }
public static void main(String[] args) throws Exception {
+
DataModel model = new FileDataModel(new File(args[0]));
- ItemSimilarity similarity = new EuclideanDistanceSimilarity(model);
- Recommender recommender = new GenericItemBasedRecommender(model,
similarity);//Use an item-item recommender
+
+ int howMany = 10;
+ if (args.length > 1) {
+ howMany = Integer.parseInt(args[1]);
+ }
+
System.out.println("Run Items");
- for (int i = 0; i < 10; i++){
- LoadEvaluator.runLoad(recommender);
+ ItemSimilarity similarity = new EuclideanDistanceSimilarity(model);
+ Recommender recommender = new GenericItemBasedRecommender(model,
similarity); // Use an item-item recommender
+ for (int i = 0; i < LOOPS; i++){
+ LoadStatistics loadStats = LoadEvaluator.runLoad(recommender, howMany);
+ System.out.println(loadStats);
}
+
System.out.println("Run Users");
UserSimilarity userSim = new EuclideanDistanceSimilarity(model);
UserNeighborhood neighborhood = new NearestNUserNeighborhood(10, userSim,
model);
recommender = new GenericUserBasedRecommender(model, neighborhood,
userSim);
- for (int i = 0; i < 10; i++){
- LoadEvaluator.runLoad(recommender);
+ for (int i = 0; i < LOOPS; i++){
+ LoadStatistics loadStats = LoadEvaluator.runLoad(recommender, howMany);
+ System.out.println(loadStats);
}
}
Modified:
mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java?rev=1204829&r1=1204828&r2=1204829&view=diff
==============================================================================
---
mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java
(original)
+++
mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java
Tue Nov 22 06:48:38 2011
@@ -29,7 +29,9 @@ import org.apache.mahout.cf.taste.eval.R
import org.apache.mahout.cf.taste.example.kddcup.DataFileIterable;
import org.apache.mahout.cf.taste.example.kddcup.KDDCupDataModel;
import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
+import org.apache.mahout.cf.taste.impl.common.FullRunningAverageAndStdDev;
import org.apache.mahout.cf.taste.impl.common.RunningAverage;
+import org.apache.mahout.cf.taste.impl.common.RunningAverageAndStdDev;
import
org.apache.mahout.cf.taste.impl.eval.AbstractDifferenceRecommenderEvaluator;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.Preference;
@@ -77,7 +79,8 @@ public final class Track1RecommenderEval
new PreferenceEstimateCallable(recommender, userID, validationPrefs,
noEstimateCounter));
}
- execute(estimateCallables, noEstimateCounter);
+ RunningAverageAndStdDev timing = new FullRunningAverageAndStdDev();
+ execute(estimateCallables, noEstimateCounter, timing);
double result = computeFinalEvaluation();
log.info("Evaluation result: {}", result);