賞金將在 6 天后到期。此問題的答案有資格獲得 50聲望賞金。 Ness想提請更多關注這個問題:
帶有代碼示例和解釋的詳細答案。
我對強化學習相當陌生,我已經構建了一個代理,它向其神經網路提供兩個輸入(第一個輸入是一個元組,其中兩個數字代表代理當前位置 | 第二個輸入是一個范圍從 0 到 3 的數字陣串列示代理從環境中接收到的請求型別)并輸出最佳移動(向前、向后、側向等......)
每集有 300 步,train_pos_nn() 中的 for 回圈需要 5 秒(每次呼叫 predict() 大約需要 20 毫秒,每次呼叫 fit() 大約需要 7 毫秒),相當于每集 25 分鐘,即太多時間。(大約需要 17 天才能完成 1000 集,這是收斂所需的集數/在 Google Colab 上花費相同的時間(編輯:即使使用 GPU 選項,并且 gpu 也無法設定為在我的本地機器上使用) )
有什么辦法可以減少代理培訓的時間嗎?
n_possible_movements = 9
MINIBATCH_SIZE = 32
class DQNAgent(object):
def __init__(self):
#self.gamma = 0.95
self.epsilon = 1.0
self.epsilon_decay = 0.8
self.epsilon_min = 0.1
self.learning_rate = 10e-4
self.tau = 1e-3
# Main models
self.model_uav_pos = self._build_pos_model()
# Target networks
self.target_model_uav_pos = self._build_pos_model()
# Copy weights
self.target_model_uav_pos.set_weights(self.model_uav_pos.get_weights())
# An array with last n steps for training
self.replay_memory_pos_nn = deque(maxlen=REPLAY_MEMORY_SIZE)
def _build_pos_model(self): # compile the DNN
# create the DNN model
dnn = self.create_pos_dnn()
opt = Adam(learning_rate=self.learning_rate) #, decay=self.epsilon_decay)
dnn.compile(loss="categorical_crossentropy", optimizer=opt, metrics=['accuracy'])
return dnn
def create_pos_dnn(self):
# initialize the input shape (The shape of an array is the number of elements in each dimension)
pos_input_shape = (2,)
requests_input_shape = (len(env.ues),)
# How many possible outputs we can have
output_nodes = n_possible_movements
# Initialize the inputs
uav_current_position = Input(shape=pos_input_shape, name='pos')
ues_requests = Input(shape=requests_input_shape, name='requests')
# Put them in a list
list_inputs = [uav_current_position, ues_requests]
# Merge all input features into a single large vector
x = layers.concatenate(list_inputs)
# Add a 1st Hidden (Dense) Layer
dense_layer_1 = Dense(512, activation="relu")(x)
# Add a 2nd Hidden (Dense) Layer
dense_layer_2 = Dense(512, activation="relu")(dense_layer_1)
# Add a 3rd Hidden (Dense) Layer
dense_layer_3 = Dense(256, activation="relu")(dense_layer_2)
# Output layer
output_layer = Dense(output_nodes, activation="softmax")(dense_layer_3)
model = Model(inputs=list_inputs, outputs=output_layer)
# return the DNN
return model
def remember_pos_nn(self, state, action, reward, next_state, done):
self.replay_memory_pos_nn.append((state, action, reward, next_state, done))
def act_upon_choosing_a_new_position(self, state): # state is a tuple (uav_position, requests_array)
if np.random.rand() <= self.epsilon: # if acting randomly, take random action
return random.randrange(n_possible_movements)
pos = np.array([state[0]])
reqs = np.array([state[1]])
act_values = self.model_uav_pos.predict(x=[pos, reqs]) # if not acting randomly, predict reward value based on current state
return np.argmax(act_values[0])
def train_pos_nn(self):
print("In Training..")
# Start training only if certain number of samples is already saved
if len(self.replay_memory_pos_nn) < MIN_REPLAY_MEMORY_SIZE:
print("Exiting Training: Replay Memory Not Full Enough...")
return
# Get a minibatch of random samples from memory replay table
minibatch = random.sample(self.replay_memory_pos_nn, MINIBATCH_SIZE)
start_time = time.time()
# Enumerate our batches
for index, (current_state, action, reward, new_current_state, done) in enumerate(minibatch):
print('...Starting Training...')
target = 0
pos = np.array([current_state[0]])
reqs = np.array([current_state[1]])
pos_next = np.array([new_current_state[0]])
reqs_next = np.array([new_current_state[1]])
if not done:
target = reward DISCOUNT * np.amax(self.target_model_uav_pos.predict(x=[pos_next, reqs_next]))
else:
target = reward
# Update Q value for given state
target_f = self.model_uav_pos.predict(x=[pos, reqs])
target_f[0][action] = target
self.model_uav_pos.fit([pos, reqs], \
target_f, \
verbose=2, \
shuffle=False, \
callbacks=None, \
epochs=1 \
)
end_time = time.time()
print("Time", end_time - start_time)
# Update target network counter every episode
self.target_train()
def target_train(self):
weights = self.model_uav_pos.get_weights()
target_weights = self.target_model_uav_pos.get_weights()
for i in range(len(target_weights)):
target_weights[i] = weights[i] * self.tau target_weights[i] * (1 - self.tau)
self.target_model_uav_pos.set_weights(target_weights)
# Main
SIZE = 100 # size of the grid the agent is in
for episode in tqdm(range(1, n_episodes 1), ascii=True, unit='episodes'):
# Reset environment and get initial state
current_state = env.reset(SIZE)
# Reset flag and start iterating until episode ends
done = False
steps_n = 300
for t in range(steps_n):
# Normalize the input (the current state)
current_state_normalized = normalize_pos_state(current_state)
# Get new position for the agent
action_pos = agent_dqn.act_upon_choosing_a_new_position(current_state_normalized)
new_state, reward, done, _ = env.step(action_pos)
agent_dqn.remember_pos_nn(current_state_normalized, action_pos, reward, normalize_pos_state(new_state), done)
current_state = new_state # not normalized
agent_dqn.train_pos_nn()
# Decay epsilon
if episode % 50 == 0:
if agent_dqn.epsilon > agent_dqn.epsilon_min:
agent_dqn.epsilon *= agent_dqn.epsilon_decay
agent_dqn.epsilon = max(agent_dqn.epsilon, agent_dqn.epsilon_min)
uj5u.com熱心網友回復:
訓練回圈中的一項性能優化是使用call模型的方法而不是呼叫predict,并用tf.function. predict適合批量推理,但有一些開銷,對于單個樣本,call可能會更快。可以在此處找到有關此差異的更多詳細資訊。出于您的目的,如何修改它可能是:
class DQNAgent(object):
def _build_pos_model(self): # compile the DNN
# create the DNN model
dnn = self.create_pos_dnn()
opt = Adam(learning_rate=self.learning_rate) #, decay=self.epsilon_decay)
dnn.compile(loss="categorical_crossentropy", optimizer=opt, metrics=['accuracy'])
dnn.call = tf.function(dnn.call)
return dnn
然后將和的每次呼叫分別更改為self.model_uav_pos.predict(..)和。self.target_model_uav_pos.predict(...)self.model_uav_pos(...)self.target_model_uav_pos(...)
進一步的潛在優化可能是JIT 編譯提供jit_compile=True給tf.function包裝器的 TF 函式,例如;
dnn.call = tf.function(dnn.call, jit_compile=True)
更新
看起來使用call方法而不是,將方法predict包裝在中,并且使用 JIT 編譯將性能提高了 2 倍(5s -> 2s),這是一個明顯的差異。對于進一步的優化,雖然我認為它們不會讓你走得更遠,而不是僅僅在可以包裝之后包裝其他計算,所以它們都成為一個可呼叫的 Tensorflow 圖。例如:calltf.functioncallcalltf.function
act_values = self.model_uav_pos(x=[pos, reqs])
return np.argmax(act_values[0])
與其np.argmax事后呼叫call,我們可以使用tf.argmax, 然后將兩者都包裝在tf.function. 所以修改后的實作可能是:
class DQNAgent(object):
def __init__(self):
#self.gamma = 0.95
self.epsilon = 1.0
self.epsilon_decay = 0.8
self.epsilon_min = 0.1
self.learning_rate = 10e-4
self.tau = 1e-3
# Main models
self.model_uav_pos = self._build_pos_model()
self.pred_model_uav = tf.function(lambda x: tf.argmax(self.model_uav_pos(x)), jit_compile=True)
# Target networks
self.target_model_uav_pos = self._build_pos_model()
# Copy weights
self.target_model_uav_pos.set_weights(self.model_uav_pos.get_weights())
self.pred_target_model_uav = tf.function(lambda x: tf.reduce_max(self.target_model_uav_pos(x)), jit_compile=True)
然后用call定義的相應新預測方法(例如,代替self.model_uav_pos(...)call self.pred_model_uav_pos(...))替換最初提出的解決方案中的每個替換,并洗掉numpy預測后的函式呼叫。注意在此實作中,dnn.call = tf.function(dnn.call)從 中洗掉_build_pos_model,因為我們稍后將進行包裝。
這種方法的好處是通過 JIT 編譯最終應用于結果的其他計算(argmax 和 max),可以通過融合操作對圖進行額外的優化。可以在此處找到有關此想法的一些其他詳細資訊以及 softmax 的簡單示例。
正如我所說,我認為這不會導致進一步的大幅改進,但它可能會在回圈中減少一些額外的時間。
uj5u.com熱心網友回復:
使用GPU(圖形處理單元)總是會使模型訓練更快。您可以按照以下步驟在 GPU 上訓練您的模型:
如何在 2022 年最終在 Windows 10 上安裝 TensorFlow 2 GPU:
- 第 1 步:找出 TF 版本及其驅動程式。
- 步驟 2:安裝 Microsoft Visual Studio
- 第 3 步:安裝 NVIDIA CUDA 工具包
- 第 4 步:安裝 cuDNN
- 第 5 步:解壓縮 ZIP 檔案夾并復制核心目錄
- 第 6 步:將 CUDA 工具包添加到 PATH
- 第 7 步:使用 Jupyter Lab 在虛擬環境中安裝 TensorFlow
(上面鏈接中有詳細說明)
但是,您可以使用Google Colab,因為它有一個 GPU 選項,不需要您進行任何安裝。您可以在 colab 設定中更改加速器:Runtime -> Change runtime type -> None/GPU/TPU.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/482349.html
