Więc co to jest A3C? Obliczenia A3C zostały ostatnio rozładowane przez grupę Google’a DeepMind, i posypały się… w zasadzie przestarzałym DQN. Było to szybsze, łatwiejsze, coraz bardziej energiczne i gotowe do osiągania znacznie lepszych wyników na standardowej baterii przedsięwzięć Profound RL. Ogólnie rzecz biorąc, mógł on pracować w spójny sposób, tak samo jak dyskretne przestrzenie aktywności. Biorąc to pod uwagę, stało się to nurkowaniem do obliczeń Deep RL dla nowych kwestii związanych z testami o złożonym stanie i przestrzeni aktywności. Prawdę mówiąc, OpenAI właśnie rozładowała interpretację A3C jako swojego “ogólnego specjalisty ds. startu” do pracy z nowym (i niezwykle zróżnicowanym) zestawem sytuacji Wszechświata.

3 As of A3C

Nieprzeprowadzony Bit leeway Entertainer Pundit jest poważnym kawałkiem. Może zaczniemy od rozładowania nazwy, a od tego momentu zaczniemy rozładowywać mechanikę samego obliczenia.

Nonconcurrent: Wcale nie tak jak DQN, gdzie samotny operator, z którym rozmawia samotny system neuronowy współpracuje z samotną sytuacją, A3C używa różnych przejawów powyższego, aby tym bardziej produktywnie się dostosować. W A3C istnieje ogólnoświatowy system i różnych operatorów specjalistycznych, z których każdy ma własny układ parametrów systemu. Każdy z tych operatorów łączy się z własnym duplikatem ziemi jednocześnie, ponieważ różni specjaliści komunikują się ze swoim otoczeniem. Wyjaśnienie, że to działa lepiej niż posiadanie samotnego specjalisty (po przekroczeniu szybkości wykonywania większej ilości pracy), jest takie, że doświadczenie każdego z operatorów jest wolne od doświadczeń innych. Wzdłuż tych linii, ogólne doświadczenia dostępne do przygotowania okazują się być stopniowo dobierane.

Entertainer Pundit: Do tej pory ten układ koncentrował się na strategiach akcentujących szacunek, na przykład, Q-learning, lub technikach cyklu podejścia, na przykład, Strategy Slope. Charakter na ekranie Pundit konsoliduje zalety tych dwóch metodyk. Ze względu na A3C, nasz system oceni zarówno wartościową pojemność V(s) (jak wielki ma być konkretny stan), jak i strategię π(s) (dużą wydajność prawdopodobieństwa działalności). Każda z nich będzie niezależną, całkowicie powiązaną warstwą siedzącą w najwyższym punkcie systemu. Zasadniczo, operator korzysta z miernika wartości (pundit), aby odświeżyć strategię (Entertainer) bardziej sprytnie niż konwencjonalne strategie nachylenia układu.

Zastosowanie Algorytmu

https://miro.medium.com/max/1316/1*Hzql_1t0-wwDxiz0C97AcQ.png

W czasie pracy nad strukturą to wykorzystanie obliczeń A3C, wykorzystałem jako punkt odniesienia wykonanie jakości przez DennyBritz i OpenAI. Te dwie, które dogłębnie przepisuję na wypadek, gdybyś chciał zobaczyć opcje w przeciwieństwie do mojego kodu tutaj. Każdy segment wstawiony tutaj jest brany poza jakimkolwiek istotnym połączeniem z danym zagadnieniem w celach instruktażowych i nie będzie działał sam. Aby zobaczyć i uruchomić pełne, użyteczne wykonanie A3C, zobacz mój skarbiec Githuba.

Ogólny schemat inżynierii kodu jest następujący:

AC_Network – Klasa ta zawiera wszystkie operacje Tensorflow do wykonania samych systemów.

Specialist – Klasa ta zawiera duplikat AC_Network, klasę domenową, podobnie jak wszystkie przesłanki do współpracy z naturą i odświeżenia systemu na całym świecie.

Podwyższony kod poziomu do budowania zdarzeń Specialist i uruchamiania ich równolegle.

Obliczenia A3C rozpoczynają się od opracowania systemu światowego. System ten będzie składał się z warstw fałdowych do przetwarzania warunków przestrzennych, ciągniętych przez warstwę LSTM do przetwarzania przelotnych warunków, wreszcie, wartych i strategicznych warstw wydajności. Poniżej znajduje się kod modelu do tworzenia wykresu systemowego.

klasa AC_Network():

def __init__(self,s_size,a_size,scope,trainer):

z tf.variable_scope(scope):

#Wejściowe i wizualne warstwy kodowania

self.inputs = tf.placeholder(shape=[None,s_size],dtype=tf.float32)

self.imageIn = tf.reshapepe(self.inputs,shape=[-1,84,84,1])

self.conv1 = slim.conv2d(activation_fn=tf.nn.elu,

inputs=self.imageIn,num_outputs=16,

kernel_size=[8,8], stride=[4,4], padding=”VALID”)

self.conv2 = slim.conv2d(activation_fn=tf.nn.elu,

inputs=self.conv1,num_outputs=32,

kernel_size=[4,4], stride=[2,2], padding=”VALID”)

hidden = slim.full_connected(slim.flatten(self.conv2),256,activation_fn=tf.nn.elu)

#Recurrent network for temporal dependencies

lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(256,state_is_tuple=True)

c_init = np.zera((1, lstm_cell.state_size.c), np.float32)

h_init = np.zera((1, lstm_cell.state_size.h), np.float32)

self.state_init = [c_init, h_init]

c_in = tf.placeholder(tf.float32, [1, lstm_cell.state_size.c])

h_in = tf.placeholder(tf.float32, [1, lstm_cell.state_size.h])

self.state_in = (c_in, h_in)

rnn_in = tf.expand_dims(ukryte, [0])

step_size = tf.shape(self.imageIn)[:1]

state_in = tf.nn.rnn_cell.LSTMStateTuple(c_in, h_in)

lstm_outputs, lstm_state = tf.nn.dynamic_rnnn(

lstm_cell, rnn_in, initial_state=state_in, sequence_length=step_size,

time_major=False)

lstm_c, lstm_h = lstm_state

self.state_out = (lstm_c[:1, :], lstm_h[:1, :])

rnn_out = tf.reshape(lstm_outputs, [-1, 256])

#Warstwy wyjściowe dla oszacowania polityki i wartości

self.policy = slim.full_connected(rnn_out,a_size,

activation_fn=tf.nn.softmax,

weights_initializer=normalized_columns_initializer(0.01),

biases_initializer=Nie ma)

self.value = slim.full_connected(rnn_out,1,

activation_fn=Nie ma,

weights_initializer=normalized_columns_initializer(1.0),

biases_initializer=Nie ma)

Następnie wielu robotników, z których każdy ma swój własny system i kondycję. Każdy z tych robotników jest uruchamiany na innym ciągu procesora, więc nie powinno być większej liczby robotników, niż jest ciągów na Twoim procesorze.

z tf.device(“/cpu:0”):

master_network = AC_Network(s_size,a_size,’global’,None) # Generate global network

num_workers = multiprocessing.cpu_count() # Set workers ot number of available CPU threads

pracownicy = []

# Tworzenie zajęć dla pracowników

dla i in range(num_workers):

workers.append(Worker(DoomGame(),i,s_size,a_size,trainer,saver,model_path))

z tf.Session() jako Sess:

Koordynator = tf.train.Coordinator()

if load_model == Prawda:

wydrukuj “Loading Model…

ckpt = tf.train.get_checkpoint_state(model_path)

saver.restore(sess,ckpt.model_checkpoint_path)

Inaczej:

sess.run(tf.global_variables_initializer())

# To tutaj dzieje się asynchroniczna magia.

# Rozpocząć proces “pracy” dla każdego pracownika w osobnym zagrożeniu.

worker_threads = []

dla pracownika w robotnikach:

worker_work = lambda: worker.work(max_episode_length,gamma,master_network,sess,coord)

t = gwintowanie.Gwintowanie(target=(worker_work))

t.start()

worker_threads.append(t)

coord.join(worker_threads)

Każdy robotnik zaczyna od ustawienia swoich parametrów systemowych na parametry systemu światowego. Możemy to zrobić poprzez opracowanie operacji Tensorflow, która ustawia każdy czynnik w specjalistycznym systemie sąsiedzkim na równi zmienną zachętę w systemie światowym.

Każdy specjalista w tym momencie kojarzy się z własnym duplikatem natury i gromadzi zrozumienie. Każdy trzyma w ręku pulę doświadczeń (postrzeganie, aktywność, wynagradzanie, robienie, szacunek), które są nieustannie dodawane do komunikacji z ziemią.

lass Worker():

….

….

….

def work(self,max_episode_length,gamma,global_AC,sess,coord):

episode_count = 0

total_step_count = 0

Print “Starting worker ” + str(self.number)

z sess.as_default(), sess.graph.as_default():

a nie coord.should_stop():

sess.run(self.update_local_ops)

episode_buffer = []

episode_values = []

episode_frames = []

episode_reward = 0

episode_step_count = 0

d = Fałszywy

self.env.new_episode()

s = self.env.get_state().screen_buffer

episode_frames.append(s)

s = process_frame(s)

rnn_state = self.local_AC.state_init

while self.env.is_episode_finished() == Fałszywy:

#Podejmij działanie używając prawdopodobieństwa z wyjścia sieciowego polityki.

a_dist,v,rnn_state = sess.run([self.local_AC.policy,self.local_AC.value,self.local_AC.state_out],

feed_dict={self.local_AC.inputs:[s],

self.local_AC.state_in[0]:rnn_state[0],

self.local_AC.state_in[1]:rnn_state[1]})

a = np.random.choice(a_dist[0],p=a_dist[0])

a = np.argmax(a_dist == a)

r = self.env.make_action(self.actions[a]) / 100.0

d = self.env.is_episode_finished()

if d == Fałszywy:

s1 = self.env.get_state().screen_buffer

episode_frames.append(s1)

s1 = process_frame(s1)

Inaczej:

s1 = s

episode_buffer.append([s,a,r,s1,d,v[0,0]])

episode_values.append(v[0,0])

episode_reward += r

s = s1

total_stepy += 1

episode_step_count += 1

#Specyficzne dla VizDoom. Śpimy w grze przez określony czas.

if self.sleep_time>0:

sleep(self.sleep_time)

# If the episode hasn’t ended, but the experience buffer is full, then we

# zrób krok aktualizacyjny używając tego doświadczenia.

if len(episode_buffer) == 30 i d != True and episode_step_count != max_episode_length – 1:

# Ponieważ nie wiemy co jest prawdziwym końcowym zwrotem, “bootstrap” z naszego aktualnego

# oszacowanie wartości.

v1 = sess.run(self.local_AC.value,

feed_dict={self.local_AC.inputs:[s],

self.local_AC.state_in[0]:rnn_state[0],

self.local_AC.state_in[1]:rnn_state[1]})[0,0]

v_l,p_l,e_l,g_n,v_n = self.train(global_AC,episode_buffer,sess,gamma,v1)

episode_buffer = []

sess.run(self.update_local_ops)

if d == Prawda:

przerwa

self.episode_rewards.append(episode_reward)

self.episode_lengths.append(episode_step_count)

self.episode_mean_values.append(np.mean(episode_values))

# Update the network using the experience buffer at the end of the episode.

v_l,p_l,e_l,g_n,v_n = self.train(global_AC,episode_buffer,sess,gamma,0.0)

Kiedy historia doświadczenia robotnika jest wystarczająco długa, używamy jej do decydowania o ograniczonym zwrocie i odrobinie swobody, i wykorzystujemy ją do obliczania wartości i podejścia do nieszczęść. Dodatkowo ustalamy entropię (H) podejścia. Porównuje się to do rozprzestrzeniania się prawdopodobieństwa aktywności. Na off szansę, że strategia przyniesie działania z umiarkowanym prawdopodobieństwem porównawczym, w tym momencie entropia będzie wysoka, ale na off szansę, że układ zaleca samotną działalność z ogromnym prawdopodobieństwem, w tym momencie entropia będzie niska. Wykorzystujemy entropię jako metodę poprawy badań, nakłaniając model do bycia tradycjonalistą w odniesieniu do jego świadomości właściwej aktywności.

Strata wartości: L = Σ(R – V(s))²

Strata polisy: L = -log(π(s)) * A(s) – β*H(π)

Robotnik w tym momencie wykorzystuje te nieszczęścia do uzyskania kątów dotyczących jego parametrów systemowych. Każdy z tych kątów jest powszechnie cięty, aby przewidzieć zbyt duże odświeżenie parametrów, które może zdestabilizować podejście.

Specjalista w tym momencie wykorzystuje skłonności do odświeżania światowych parametrów systemowych. Wzdłuż tych linii, system światowy jest stale odświeżany przez każdego ze specjalistów, ponieważ współpracują oni ze swoim stanem.

klasa AC_Network():

def __init__(self,s_size,a_size,scope,trainer):

….

….

….

if scope != “globalny”:

self.actions = tf.placeholder(shape=[None],dtype=tf.int32)

self.actions_onehot = tf.one_hot(self.actions,a_size,dtype=tf.float32)

self.target_v = tf.placeholder(shape=[None],dtype=tf.float32)

self.advantages = tf.placeholder(shape=[None],dtype=tf.float32)

self.responsible_outputs = tf.reduce_sum(self.policy * self.actions_onehot, [1])

#Loss functions

self.value_loss = 0,5 * tf.reduce_sum(tf.square(self.target_v – tf.reshape(self.value,[-1])))

self.entropy = – tf.reduce_sum(self.policy * tf.log(self.policy))

self.policy_loss = -tf.reduce_sum(tf.log(self.responsible_outputs)*self.advantages)

self.loss = 0,5 * self.value_loss + self.policy_loss – self.entropy * 0,01

#Get gradienty z sieci lokalnej wykorzystujące lokalne straty

local_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, zakres)

self.gradients = tf.gradients(self.loss,local_vars)

self.var_norms = tf.global_norm(local_vars)

grads,self.grad_norms = tf.clip_by_global_norm(self.gradients,40.0)

#Zastosuj lokalne gradienty do globalnej sieci

global_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, ‘global’)

self.apply_grads = trainer.apply_gradients(zip(grads,global_vars))

klasa Robotnik():

….

….

….

def train(self,global_AC,rollout,sess,gamma,bootstrap_value):

rollout = np.array(rollout)

obserwacje = rollout[:,0]

działania = rollout[:,1]

nagrody = rollout[:,2]

next_observations = rollout[:,3]

wartości = rollout[:,5]

# Tutaj bierzemy nagrody i wartości z rolki, i używamy ich do

# generować przewagę i zdyskontowane zwroty.

# Funkcja przewagi wykorzystuje “Generalized Advantage Estimation”.

self.rewards_plus = np.asarray(rewards.tolist() + [bootstrap_value])

discounted_rewards = rabat(self.rewards_plus,gamma)[:-1]

self.value_plus = np.asarray(values.tolist() + [bootstrap_value])

zalety = nagrody + gamma * self.value_plus[1:] – self.value_plus[:-1]

korzyści = rabat(korzyści, gamma)

# Aktualizacja globalnej sieci przy użyciu gradientów od strat

# Generuj statystyki sieciowe, aby okresowo zapisywać

rnn_state = self.local_AC.state_init

feed_dict = {self.local_AC.target_v:discounted_rewards,

self.local_AC.inputs:np.vstack(obserwacje),

self.local_AC.actions:actions,

self.local_AC.advantages:advantages,

self.local_AC.state_in[0]:rnn_state[0],

self.local_AC.state_in[1]:rnn_state[1]}

v_l,p_l,e_l,g_n,v_n,_ = sess.run([self.local_AC.value_loss,

self.local_AC.policy_loss,

self.local_AC.entropy,

self.local_AC.grad_norms,

self.local_AC.var_norms,

self.local_AC.apply_grads],

feed_dict=feed_dict)

return v_l / len(rollout),p_l / len(rollout),e_l / len(rollout), g_n,v_n

Po dokonaniu skutecznej aktualizacji systemu na całym świecie, cała procedura zostaje zrewidowana! W tym momencie robotnik resetuje swoje własne parametry systemowe do parametrów systemu światowego i procedura rozpoczyna się ponownie.