Skip to content

Commit 5626710

Browse files
authored
Update step calculation. Add translation of vector instead of magnitude (#511)
* Update step calculation. Add translation of vector instead of magnitude * Remove concept of magnitude * fix unit tests * PR feedback
1 parent 9bdca37 commit 5626710

14 files changed

+221
-612
lines changed

experiments/config_command_experiment.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,6 @@ def _fill_config(self):
4040
flags=['--radius'],
4141
default_value=3,
4242
description='The size of the neighborhood radius'))
43-
self._add_config(
44-
ConfigField('magnitude',
45-
field_type=ConfigPrimitive(int),
46-
flags=['--magnitude'],
47-
default_value=20,
48-
description='The size of each step'))
4943
self._add_config(
5044
ConfigField('min_mbs_index',
5145
field_type=ConfigPrimitive(int),

experiments/evaluate_config_generator.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ def store_results(self):
6666
file_writer = ExperimentFileWriter(
6767
self._output_path, file_name=f"output_{self._model_name}.csv")
6868
file_writer.write(self._checkpoint_data, self._profile_data,
69-
configs["radius"], configs["magnitude"],
70-
configs["min_initialized"])
69+
configs["radius"], configs["min_initialized"])
7170

7271
def _run_generator(self, cg):
7372
for run_config in cg.get_configs():

experiments/experiment_file_writer.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ExperimentFileWriter:
2525
field_names = [
2626
"overall_num_measurements", "overall_best_throughput",
2727
"quick_num_measurements", "missing_num_measurements",
28-
"quick_throughput", "radius", "magnitude", "min_initialized"
28+
"quick_throughput", "radius", "min_initialized"
2929
]
3030

3131
def __init__(self, output_path, file_name="output_vgg19_libtorch.csv"):
@@ -38,8 +38,7 @@ def __init__(self, output_path, file_name="output_vgg19_libtorch.csv"):
3838
writer = csv.DictWriter(csv_file, fieldnames=self.field_names)
3939
writer.writeheader()
4040

41-
def write(self, checkpoint_data, profile_data, radius, magnitude,
42-
min_initialized):
41+
def write(self, checkpoint_data, profile_data, radius, min_initialized):
4342
try:
4443
with open(self._filename, mode="a") as csv_file:
4544
writer = csv.DictWriter(csv_file, fieldnames=self.field_names)
@@ -62,7 +61,6 @@ def write(self, checkpoint_data, profile_data, radius, magnitude,
6261
"quick_throughput":
6362
quick_best_measurement.get_non_gpu_metric_value("perf_throughput"),
6463
"radius": radius,
65-
"magnitude": magnitude,
6664
"min_initialized": min_initialized
6765
})
6866
# yapf: enable

experiments/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
#
1717
# Example usage:
1818
#
19-
# python3 main.py --model-name resnet50_libtorch --generator BruteRunConfigGenerator --run-config-search-max-model-batch-size 2
20-
# python3 main.py --model-name resnet50_libtorch --generator QuickRunConfigGenerator --magnitude 5
19+
# python3 main.py --model-name resnet50_libtorch --run-config-search-mode=brute --run-config-search-max-model-batch-size 2
20+
# python3 main.py --model-name resnet50_libtorch --run-config-search-mode=quick --radius 5
2121
#####################
2222

2323
from evaluate_config_generator import EvaluateConfigGenerator

experiments/start_profiles.sh

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,15 @@ CHECKPOINT_DIR="/mnt/nvdl/datasets/inferenceserver/model_analyzer_profile_result
1717

1818
for model in inception_v1_graphdef resnet50_libtorch vgg19_libtorch; do
1919
for radius in {2..8}; do
20-
for magnitude in {1..8}; do
21-
for min_initialized in {2..8}; do
22-
echo "Profiling $model (radius = $radius, magnitude = $magnitude, min-initialized = $min_initialized)"
23-
python3 main.py --save \
24-
--model-name $model \
25-
--generator QuickRunConfigGenerator \
26-
--data-path $CHECKPOINT_DIR \
27-
--output-path output \
28-
--radius $radius \
29-
--magnitude $magnitude \
30-
--min-initialized $min_initialized
31-
done
20+
for min_initialized in {2..8}; do
21+
echo "Profiling $model (radius = $radius, min-initialized = $min_initialized)"
22+
python3 main.py --save \
23+
--model-name $model \
24+
--run-config-search-mode quick \
25+
--data-path $CHECKPOINT_DIR \
26+
--output-path output \
27+
--radius $radius \
28+
--min-initialized $min_initialized
3229
done
3330
done
3431
done

model_analyzer/config/generate/neighborhood.py

Lines changed: 72 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ class Neighborhood:
3030
a 'home' coordinate
3131
"""
3232

33+
# This defines the bounds of how the vector calculated from
34+
# measurements is converted to a step vector.
35+
#
36+
# The translation will return the lowest index that has a value greater
37+
# than the input value.
38+
#
39+
# For example, if the input is greater than the value in index 1 but less than
40+
# the value in index 2, the resulting step will be 1
41+
#
42+
TRANSLATION_LIST = [0.09, 0.3, 1.0]
43+
3344
def __init__(self, neighborhood_config: NeighborhoodConfig,
3445
home_coordinate: Coordinate):
3546
"""
@@ -90,26 +101,14 @@ def force_slow_mode(self):
90101
"""
91102
self._force_slow_mode = True
92103

93-
def calculate_new_coordinate(self,
94-
magnitude: int,
95-
enable_clipping: bool = True,
96-
clip_value: int = 2) -> Coordinate:
104+
def determine_new_home(self) -> Coordinate:
97105
"""
98106
Based on the measurements in the neighborhood, determine where
99107
the next location should be.
100108
101109
If the neighborhood is in slow mode, return the best found measurement
102110
Otherwise calculate a new coordinate from the measurements
103111
104-
Parameters
105-
----------
106-
magnitude
107-
How large of a step to take
108-
enable_clipping
109-
Determines whether or not to clip the final step vector.
110-
clip_value
111-
What value to clip the vector at, if it is enabled
112-
113112
Returns
114113
-------
115114
new_coordinate
@@ -119,8 +118,7 @@ def calculate_new_coordinate(self,
119118
if self._is_slow_mode():
120119
return self._get_best_coordinate_found()
121120
else:
122-
return self._calculate_new_coordinate(magnitude, enable_clipping,
123-
clip_value)
121+
return self._calculate_new_home()
124122

125123
def _get_best_coordinate_found(self) -> Coordinate:
126124
vectors, measurements = self._get_measurements_passing_constraints()
@@ -139,48 +137,31 @@ def _get_best_coordinate_found(self) -> Coordinate:
139137
best_coordinate = self._home_coordinate + best_vector
140138
return best_coordinate
141139

142-
def _calculate_new_coordinate(self, magnitude, enable_clipping,
143-
clip_value) -> Coordinate:
144-
145-
step_vector = self._get_step_vector() * magnitude
146-
147-
if enable_clipping:
148-
step_vector = self._clip_vector_values(vector=step_vector,
149-
clip_value=clip_value)
150-
step_vector.round()
151-
140+
def _calculate_new_home(self) -> Coordinate:
141+
step_vector = self._get_step_vector()
142+
step_vector = self._translate_step_vector(step_vector,
143+
Neighborhood.TRANSLATION_LIST)
152144
tmp_new_coordinate = self._home_coordinate + step_vector
153145
new_coordinate = self._clamp_coordinate_to_bounds(tmp_new_coordinate)
154146
return new_coordinate
155147

156-
def _clip_vector_values(self, vector: Coordinate,
157-
clip_value: int) -> Coordinate:
158-
"""
159-
Clip the values of the vector to be within the range of
160-
[-clip_value, clip_value]. The clipping preserves the direction
161-
of the vector (e.g. if the clip_value is 2, then [10, 5] will be
162-
clipped to [2, 1] instead of [2, 2]).
163-
164-
Parameters
165-
----------
166-
vector
167-
an input vector that may require clipping
168-
clip_value
169-
a non-negative integer that bounds the values of the input vector
148+
def _translate_step_vector(self, step_vector: Coordinate,
149+
translate_list: List[float]):
170150

171-
Returns
172-
-------
173-
vector
174-
a vector with all of its values within [-clip_value, clip_value]
175-
"""
176-
assert clip_value >= 0, "clip_value must be non-negative number."
151+
for i, v in enumerate(step_vector):
152+
step_vector[i] = self._translate_value(v, translate_list)
177153

178-
max_value = max(abs(c) for c in vector)
154+
return step_vector
179155

180-
if max_value > clip_value and max_value != 0:
181-
for i in range(len(vector)):
182-
vector[i] = clip_value * vector[i] / max_value
183-
return vector
156+
def _translate_value(self, value: float,
157+
translation_list: List[float]) -> int:
158+
ret = 0
159+
for index, bound in enumerate(translation_list):
160+
if value > 0 and value > bound:
161+
ret = index + 1
162+
if value < 0 and value < -1 * bound:
163+
ret = -1 * (index + 1)
164+
return ret
184165

185166
def pick_coordinate_to_initialize(self) -> Optional[Coordinate]:
186167
"""
@@ -272,8 +253,7 @@ def _enumerate_all_values_in_bounds(
272253
self, bounds: List[List[int]]) -> List[List[int]]:
273254
possible_index_values = []
274255
for bound in bounds:
275-
possible_index_values.append(list(range(bound[0], bound[1])))
276-
256+
possible_index_values.append(list(range(bound[0], bound[1] + 1)))
277257
tuples = list(product(*possible_index_values))
278258
return [list(x) for x in tuples]
279259

@@ -302,95 +282,62 @@ def _get_step_vector(self) -> Coordinate:
302282
Calculate a vector that indicates a direction to step from the
303283
home coordinate (current center).
304284
305-
If the home coordinate is passing the constraints, the method
306-
calculates the step vector based on the objectives given.
307-
Otherwise, it calculates the step vector based on the constraints
308-
so that it steps toward the region that passes the constraints.
309-
310285
Returns
311286
-------
312287
step_vector
313288
a coordinate that tells the direction to move.
314289
"""
315-
home_measurement = self._get_home_measurement()
316290

317-
assert home_measurement is not None, "Home measurement cannot be NoneType."
291+
compare_constraints = not self._is_home_passing_constraints()
292+
return self._calculate_step_vector_from_measurements(
293+
compare_constraints=compare_constraints)
318294

319-
if self._is_home_passing_constraints():
320-
return self._optimize_for_objectives(home_measurement)
295+
def _calculate_step_vector_from_measurements(
296+
self, compare_constraints: bool) -> Coordinate:
321297

322-
return self._optimize_for_constraints(home_measurement)
323-
324-
def _optimize_for_objectives(
325-
self, home_measurement: RunConfigMeasurement) -> Coordinate:
326-
"""
327-
Calculate a step vector that maximizes the current objectives.
328-
If no vectors are provided, return zero vector.
329-
330-
Parameters
331-
----------
332-
vectors
333-
list of vectors from home coordinate to the neighboring
334-
coordinates that are passing constraints
335-
measurements
336-
list of measurements of the neighboring coordinates that
337-
are passing constraints
298+
home_measurement = self._get_home_measurement()
299+
vectors, measurements = self._get_all_visited_measurements()
338300

339-
Returns
340-
-------
341-
step_vector
342-
a coordinate that tells the direction to move.
343-
"""
344-
vectors, measurements = self._get_measurements_passing_constraints()
345-
step_vector = Coordinate([0] * self._config.get_num_dimensions())
301+
# This function should only ever be called if all are passing or none are passing
302+
_, p = self._get_measurements_passing_constraints()
303+
assert (len(p) == 0 or len(p) == len(measurements))
346304

347305
if not vectors:
348-
return step_vector
349-
350-
for vector, measurement in zip(vectors, measurements):
351-
weight = home_measurement.compare_measurements(measurement)
352-
step_vector += vector * weight
353-
354-
step_vector /= len(vectors)
355-
return step_vector
306+
return Coordinate([0] * self._config.get_num_dimensions())
356307

357-
def _optimize_for_constraints(
358-
self, home_measurement: RunConfigMeasurement) -> Coordinate:
359-
"""
360-
Calculate a step vector that steps toward the coordinates that
361-
pass the constraints (set default weights to 1.0). When no vectors
362-
are provided (meaning there are no neighbors passing constraints),
363-
continue with the neighbors that are not passing constraints by
364-
comparing how much they are close to passing constraints.
308+
weights = []
309+
for m in measurements:
310+
if compare_constraints:
311+
weight = home_measurement.compare_constraints(m)
312+
else:
313+
weight = home_measurement.compare_measurements(m)
314+
weights.append(weight)
365315

366-
Parameters
367-
----------
368-
vectors
369-
list of vectors from home coordinate to the neighboring
370-
coordinates that are passing constraints
371-
measurements
372-
list of measurements of the neighboring coordinates that
373-
are passing constraints
316+
return self._calculate_step_vector_from_vectors_and_weights(
317+
vectors, weights)
374318

375-
Returns
376-
-------
377-
step_vector
378-
a coordinate that tells the direction to move.
379-
"""
380-
vectors, measurements = self._get_measurements_passing_constraints()
319+
def _calculate_step_vector_from_vectors_and_weights(self, vectors, weights):
381320
step_vector = Coordinate([0] * self._config.get_num_dimensions())
321+
dim_sum_vector = Coordinate([0] * self._config.get_num_dimensions())
322+
323+
# For each dimension -
324+
# if non zero, add weight (inverting if dimension is negative)
325+
# divide by sum of coordinate of that dimension
326+
for vector, weight in zip(vectors, weights):
327+
328+
for dim, v in enumerate(vector):
329+
if v:
330+
if v > 0:
331+
step_vector[dim] += weight
332+
dim_sum_vector[dim] += v
333+
else:
334+
step_vector[dim] -= weight
335+
dim_sum_vector[dim] -= v
336+
337+
for dim, v in enumerate(dim_sum_vector):
338+
if v:
339+
step_vector[dim] /= v
382340

383-
if not vectors:
384-
vectors, measurements = self._get_all_visited_measurements()
385-
386-
for vector, measurement in zip(vectors, measurements):
387-
weight = home_measurement.compare_constraints(measurement)
388-
if measurement.is_passing_constraints():
389-
weight = 1.0 # when home fails & neighbor passes
390-
391-
step_vector += vector * weight
392-
393-
step_vector /= len(vectors)
394341
return step_vector
395342

396343
def _get_all_visited_measurements(
@@ -405,7 +352,6 @@ def _get_all_visited_measurements(
405352
collection of vectors and their measurements.
406353
"""
407354
visited_coordinates = self._get_visited_coordinates()
408-
409355
vectors = []
410356
measurements = []
411357
for coordinate in visited_coordinates:

0 commit comments

Comments
 (0)