google-research
256 строк · 9.1 Кб
1# coding=utf-8
2# Copyright 2024 The Google Research Authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""GON experimental code on Rosenbrock and Griewank data."""
17
18from __future__ import absolute_import
19from __future__ import division
20from __future__ import print_function
21
22import random
23from absl import app
24from absl import flags
25import numpy as np
26import tensorflow as tf
27import tensorflow_lattice as tfl
28
29_CGON_OR_GON = flags.DEFINE_string("cgon_or_gon", "BOTH", "CGON, GON or BOTH")
30# Data generation hparams
31_NUM_EXAMPLES = flags.DEFINE_integer("num_examples", 10000,
32"number of training examples.")
33_INPUT_DIM = flags.DEFINE_integer("input_dim", 16, "number input dimensions.")
34_BOUND = flags.DEFINE_float("bound", 2.0, "(soft) bound for sampling.")
35_NOISE_SIGNAL_RATIO = flags.DEFINE_float(
36"noise_signal_ratio", 0.25,
37"standard deviation of the noise as a factor of the target function value "
38"in the target function.")
39# GON/CGON hparams
40_LATTICE_DIM = flags.DEFINE_integer("lattice_dim", 3,
41"number GON lattice input dimensions.")
42# Training hparams
43_STEPS = flags.DEFINE_integer("steps", 100000, "number of training steps.")
44
45
46def sample_from_uniform_square(count=1000, dim=2):
47points = np.random.uniform(low=-_BOUND, high=_BOUND, size=(count, dim))
48return points
49
50
51def rosenbrock(points, noise_signal_ratio=0.0):
52summation = 0
53for i in range(_INPUT_DIM - 1):
54summation += ((1.0 - points[:, i])**2 + 100.0 *
55(points[:, i + 1] - points[:, i]**2)**2)
56noise = np.random.normal(
57scale=abs(summation * noise_signal_ratio), size=len(points))
58return summation + noise
59
60
61def griewank(points, noise_signal_ratio=0.0):
62summation = 0
63product = 1
64for i in range(_INPUT_DIM):
65summation += (points[:, i] - 1.0)**2
66product *= np.cos((points[:, i] - 1.0) / np.sqrt(i + 1))
67y = 1 + summation / 4000 - product
68noise = np.random.normal(scale=abs(y * noise_signal_ratio), size=len(points))
69return y + noise
70
71
72def parabola(points, noise_signal_ratio=0.0):
73summation = 0
74for i in range(_INPUT_DIM):
75summation += (points[:, i] - 1.0)**2
76noise = np.random.normal(
77scale=abs(summation * noise_signal_ratio), size=len(points))
78return summation + noise
79
80
81# Global Optimization Networks (GON):
82def build_rtl_gon(lattice_dim):
83"""Build GON model."""
84input_layer = tf.keras.layers.Input(shape=(_INPUT_DIM,))
85calibrated_output = tfl.layers.PWLCalibration(
86input_keypoints=np.linspace(-_BOUND, _BOUND, 10),
87units=_INPUT_DIM,
88output_min=-1.0,
89output_max=1.0,
90clamp_min=True,
91clamp_max=True,
92monotonicity="increasing",
93name="input_calibration",
94)(
95input_layer)
96lattice_inputs = []
97for _ in range(_INPUT_DIM):
98indices = random.sample(range(_INPUT_DIM), lattice_dim)
99lattice_inputs.append(tf.gather(calibrated_output, indices, axis=1) + 1.0)
100lattice_input = tf.stack(lattice_inputs, axis=1)
101lattice_output_layer = tfl.layers.Lattice(
102lattice_sizes=[3] * lattice_dim,
103units=_INPUT_DIM,
104joint_unimodalities=(list(range(lattice_dim)), "valley"),
105kernel_initializer="random_uniform",
106)(
107lattice_input)
108output_layer = tf.keras.layers.Dense(
109units=1, kernel_constraint=tf.keras.constraints.NonNeg())(
110lattice_output_layer)
111keras_model = tf.keras.models.Model(
112inputs=[input_layer], outputs=output_layer)
113keras_model.compile(
114loss="mean_squared_error", optimizer=tf.keras.optimizers.Adam())
115return keras_model
116
117
118# Conditional Global Optimization Networks (CGON):
119def build_rtl_cgon(lattice_dim, gon_dim):
120"""Build GON model."""
121input_layer = tf.keras.layers.Input(shape=(_INPUT_DIM,))
122nongon_dim = _INPUT_DIM - gon_dim
123gon_input_layer, nongon_input_layer = tf.split(
124input_layer, [gon_dim, nongon_dim], axis=1)
125gon_calibrated_output = tfl.layers.PWLCalibration(
126input_keypoints=np.linspace(-_BOUND, _BOUND, 10),
127units=gon_dim,
128monotonicity="increasing",
129output_min=-1.0,
130output_max=1.0,
131clamp_min=True,
132clamp_max=True,
133name="gon_calibration",
134)(
135gon_input_layer)
136gon_rtl_input_layer = []
137for i in range(gon_dim):
138nongon_calibrated_output = tf.reduce_mean(
139tfl.layers.PWLCalibration(
140input_keypoints=np.linspace(-_BOUND, _BOUND, 10),
141units=nongon_dim,
142output_min=-1.0,
143output_max=1.0,
144name="nongon_pwl_" + str(i))(nongon_input_layer),
145axis=1,
146keepdims=True)
147gon_rtl_input_layer.append(nongon_calibrated_output +
148tf.gather(gon_calibrated_output, [i], axis=1))
149gon_rtl_input_layer = tf.tanh(tf.concat(gon_rtl_input_layer, axis=1)) + 1.0
150lattice_inputs = []
151for _ in range(gon_dim):
152gon_indices = random.sample(range(gon_dim), lattice_dim)
153gon_lattice_input = tf.gather(gon_rtl_input_layer, gon_indices, axis=1)
154lattice_inputs.append(gon_lattice_input)
155lattice_input = tf.stack(lattice_inputs, axis=1)
156lattice_output_layer = tfl.layers.Lattice(
157lattice_sizes=[3] * lattice_dim,
158units=gon_dim,
159joint_unimodalities=(list(range(lattice_dim)), "valley"),
160kernel_initializer="random_uniform",
161)(
162lattice_input)
163output_layer = tf.keras.layers.Dense(
164units=1, kernel_constraint=tf.keras.constraints.NonNeg())(
165lattice_output_layer)
166keras_model = tf.keras.models.Model(
167inputs=[input_layer], outputs=output_layer)
168keras_model.compile(
169loss="mean_squared_error", optimizer=tf.keras.optimizers.Adam())
170return keras_model
171
172
173def get_optim_from_cal(calibrator_weights, target=0.0):
174"""Get Argmin Through Inverting the Calibrators."""
175keypoints_x = np.linspace(-_BOUND, _BOUND, 10)
176keypoints_y = np.cumsum(calibrator_weights)
177if keypoints_y[0] > target:
178return keypoints_x[0]
179for i in range(len(keypoints_x) - 1):
180if keypoints_y[i] < target and keypoints_y[i + 1] > target:
181w = (keypoints_y[i + 1] - target) / (keypoints_y[i + 1] - keypoints_y[i])
182return keypoints_x[i + 1] - w * (keypoints_x[i + 1] - keypoints_x[i])
183return keypoints_x[-1]
184
185
186def main(_):
187data_generation_function = griewank # rosenbrock / griewank / parabola
188# The global minimizer is at (1.0, 1.0, ..., 1.0).
189argmin_true = 1.0
190
191# Generate Data
192training_inputs = sample_from_uniform_square(
193count=_NUM_EXAMPLES, dim=_INPUT_DIM)
194labels = (
195data_generation_function(
196training_inputs, noise_signal_ratio=_NOISE_SIGNAL_RATIO) /
197data_generation_function(np.array([[-_BOUND] * _INPUT_DIM])))
198
199# Simulation for GON
200if _CGON_OR_GON != "CGON":
201# Global Optimization Networks
202keras_model_gon = build_rtl_gon(lattice_dim=_LATTICE_DIM)
203keras_model_gon.fit(
204training_inputs,
205labels,
206batch_size=100,
207epochs=int(_STEPS * 100 / _NUM_EXAMPLES),
208verbose=0,
209)
210result_gon = []
211for i in range(_INPUT_DIM):
212result_gon.append(
213get_optim_from_cal(
214keras_model_gon.get_layer("input_calibration").get_weights()[0]
215[:, i]))
216# f(argmin_hat)
217print("[metric] GON_val=" +
218str(data_generation_function(np.array([result_gon]))[0]))
219# ||argmin_hat - argmin_true||^2
220print("[metric] GON_dist=" + str(
221np.sum([(a - argmin_true) * (a - argmin_true) for a in result_gon])))
222
223# Simulation for CGON
224if _CGON_OR_GON != "GON":
225# Input features for each example consists of first optimization_dim for
226# optimiaztion, and then conditional_dim conditional inputs.
227optimization_dim = int(_INPUT_DIM / 4 * 3)
228conditional_dim = int(_INPUT_DIM / 4)
229# Conditional Global Optimization Networks
230keras_model_cgon = build_rtl_cgon(
231lattice_dim=_LATTICE_DIM, gon_dim=optimization_dim)
232keras_model_cgon.fit(
233training_inputs,
234labels,
235batch_size=100,
236epochs=int(_STEPS * 100 / _NUM_EXAMPLES),
237verbose=0,
238)
239result_cgon = []
240for i in range(optimization_dim):
241target = -tf.reduce_mean(
242keras_model_cgon.get_layer("nongon_pwl_" + str(i))(tf.zeros(
243shape=[1, conditional_dim], dtype=tf.float32))).numpy()
244result_cgon.append(
245get_optim_from_cal(
246keras_model_cgon.get_layer("gon_calibration").get_weights()[0][:,
247i],
248target))
249result_cgon = result_cgon + [0.0] * conditional_dim
250# f(argmin_hat)
251print("[metric] CGON_val=" +
252str(data_generation_function(np.array([result_cgon]))[0]))
253
254
255if __name__ == "__main__":
256app.run(main)
257