2013-07-29 46 views
5

Ben Sutton & Barto'nun ebook'unu kullanıyorum Takviye Öğrenme: Takviye öğrenmeyi incelemek için bir Giriş. Ben action-value page üzerinde sonuçları (araziler) taklit etmeye çalışan bazı sorunlar yaşıyorum.n-silahlı bandit simülasyonu R

Daha ayrıntılı olarak, her görev için greedy değerini nasıl taklit edebilirim? kitap diyor ki:

... biz onlar 1000 oyunlarında üzerinde deneyime sahip geliştirmek olarak performans ve çeşitli yöntemler davranışını ...

Ben de izlemek zorunda tahmin çizebilirsiniz araştırmacısı değerleri daha iyi olanlar bulundu. Sorun, açgözlü yaklaşımını kullanarak bunu nasıl yapılacağıdır - keşif hareketleri olmadığından, açgözlü davranışı nedir nedir?

Tüm yorumlar ve cevaplar için teşekkürler!

GÜNCELLEME: Cevabımdaki kodlara bakın.

+1

Eğer alıyorsanız ve ne (aynı zamanda elde edilecek bekliyorsunuz ne çıktı, bir' tohum eklemek isteyebilirsiniz Numpy gelen basitçe np.random.rand() R kullanmak değil, Başkalarının kopyalayabildiğini.) –

+0

Sorun, bir vektör V (her x sütunu) verildiğinde * açgözlü * değeri elde etmektir. Eğer runif (1) Fernando

+0

Belki de kodları, sadece kodunuzu kopyalayıp yapıştırarak oluşturulacak şekilde değiştirin. Kodunuzu kopyalayıp yapıştırdığımda hiçbir şey iade edilmez. Verileri döndürmek için ilk iki işlevi şimdi kazandım, ancak henüz üretilen parçaları almamıştım. –

cevap

4

. eps player, kitabın işaret ettiği gibi, keşif hareketlerinden dolayı açgözlü oyuncusunu atlatmalıdır. kod yavaş ve bazı optimizasyonlar gerekiyor, ama işte burada:

enter image description here

get.testbed = function(arms = 10, plays = 500, u = 0, sdev.arm = 1, sdev.rewards = 1){ 

    optimal = rnorm(arms, u, sdev.arm) 
    rewards = sapply(optimal, function(x)rnorm(plays, x, sdev.rewards)) 

    list(optimal = optimal, rewards = rewards) 
} 

play.slots = function(arms = 10, plays = 500, u = 0, sdev.arm = 1, sdev.rewards = 1, eps = 0.1){ 

    testbed = get.testbed(arms, plays, u, sdev.arm, sdev.rewards) 
    optimal = testbed$optimal 
    rewards = testbed$rewards 

    optim.index = which.max(optimal) 
    slot.rewards = rep(0, arms) 
    reward.hist = rep(0, plays) 
    optimal.hist = rep(0, plays) 
    pulls = rep(0, arms) 
    probs = runif(plays) 

    # vetorizar 
    for (i in 1:plays){ 

     ## dont use ifelse() in this case 
     ## idx = ifelse(probs[i] < eps, sample(arms, 1), which.max(slot.rewards)) 

     idx = if (probs[i] < eps) sample(arms, 1) else which.max(slot.rewards) 
     reward.hist[i] = rewards[i, idx] 

     if (idx == optim.index) 
     optimal.hist[i] = 1 

     slot.rewards[idx] = slot.rewards[idx] + (rewards[i, idx] - slot.rewards[idx])/(pulls[idx] + 1) 
     pulls[idx] = pulls[idx] + 1 
    } 

    list(slot.rewards = slot.rewards, reward.hist = reward.hist, optimal.hist = optimal.hist, pulls = pulls) 
} 

do.simulation = function(N = 100, arms = 10, plays = 500, u = 0, sdev.arm = 1, sdev.rewards = 1, eps = c(0.0, 0.01, 0.1)){ 

    n.players = length(eps) 
    col.names = paste('eps', eps) 
    rewards.hist = matrix(0, nrow = plays, ncol = n.players) 
    optim.hist = matrix(0, nrow = plays, ncol = n.players) 
    colnames(rewards.hist) = col.names 
    colnames(optim.hist) = col.names 

    for (p in 1:n.players){ 
    for (i in 1:N){ 
     play.results = play.slots(arms, plays, u, sdev.arm, sdev.rewards, eps[p]) 
     rewards.hist[, p] = rewards.hist[, p] + play.results$reward.hist 
     optim.hist[, p] = optim.hist[, p] + play.results$optimal.hist 
    } 
    } 

    rewards.hist = rewards.hist/N 
    optim.hist = optim.hist/N 
    optim.hist = apply(optim.hist, 2, function(x)cumsum(x)/(1:plays)) 

    ### Plot helper ### 
    plot.result = function(x, n.series, colors, leg.names, ...){ 
    for (i in 1:n.series){ 
     if (i == 1) 
     plot.ts(x[, i], ylim = 2*range(x), col = colors[i], ...) 
     else 
     lines(x[, i], col = colors[i], ...) 
     grid(col = 'lightgray') 
    } 
    legend('topleft', leg.names, col = colors, lwd = 2, cex = 0.6, box.lwd = NA) 
    } 
    ### Plot helper ### 

    #### Plots #### 
    require(RColorBrewer) 
    colors = brewer.pal(n.players + 3, 'Set2') 
    op <-par(mfrow = c(2, 1), no.readonly = TRUE) 

    plot.result(rewards.hist, n.players, colors, col.names, xlab = 'Plays', ylab = 'Average reward', lwd = 2) 
    plot.result(optim.hist, n.players, colors, col.names, xlab = 'Plays', ylab = 'Optimal move %', lwd = 2) 
    #### Plots #### 

    par(op) 
} 

sadece

do.simulation(N = 100, arms = 10, eps = c(0, 0.01, 0.1)) 
+0

Bu çok güzel.Çok stratejileri karşılaştıran bir kod göndermek ister misiniz ben gibi kitap n? Belki bunu daha sonra inceleyebilir ve üçüncü bir stratejiyi nasıl ekleyeceğimi anlayabilirim. Bunu göndermek için teşekkürler. –

+0

Bitti, bir göz atın! – Fernando

1

bu defa bizim sohbet dayalı da budur: Sonunda bu hakkın

set.seed(1) 

getRewardsGaussian <- function(arms, plays) { 
## assuming each action has a normal distribution 

    # first generate new means 
    QStar <- rnorm(arms, 0, 1) 

    # then for each mean, generate `play`-many samples 
    sapply(QStar, function(u) 
    rnorm(plays, u, 1)) 
} 


CalculateRewardsPerMethod <- function(arms=7, epsi1=0.01, epsi2=0.1 
        , plays=1000, methods=c("greedy", "epsi1", "epsi2")) { 

    # names for easy handling 
    names(methods) <- methods 
    arm.names <- paste0("Arm", ifelse((1:arms)<10, 0, ""), 1:arms) 

    # this could be different if not all actions' rewards have a gaussian dist. 
    rewards.source <- getRewardsGaussian(arms, plays) 

    # Three dimensional array to track running averages of each method 
    running.avgs <- 
    array(0, dim=c(plays, arms, length(methods)) 
      , dimnames=list(PlayNo.=NULL, Arm=arm.names, Method=methods)) 

    # Three dimensional array to track the outcome of each play, according to each method 
    rewards.received <- 
    array(NA_real_, dim=c(plays, 2, length(methods)) 
        , dimnames=list(PlayNo.=seq(plays), Outcome=c("Arm", "Reward"), Method=methods)) 


    # define the function internally to not have to pass running.avgs 
    chooseAnArm <- function(p) { 
    # Note that in a tie, which.max returns the lowest value, which is what we want 
    maxes <- apply(running.avgs[p, ,methods, drop=FALSE], 3, which.max) 

    # Note: deliberately drawing two separate random numbers and keeping this as 
    #  two lines of code to accent that the two draws should not be related 
    if(runif(1) < epsi1) 
     maxes["epsi1"] <- sample(arms, 1) 

    if(runif(1) < epsi2) 
     maxes["epsi2"] <- sample(arms, 1) 

    return(maxes) 
    } 

    ## TODO: Perform each action at least once, then select according to algorithm 
    ## Starting points. Everyone starts at machine 3 
    choice <- c(3, 3, 3) 
    reward <- rewards.source[1, choice] 
    ## First run, slightly different 
    rewards.received[1,,] <- rbind(choice, reward) 
    running.avgs[1, choice, ] <- reward # if different starting points, this needs to change like below 

    ## HERE IS WHERE WE START PULLING THE LEVERS ## 
    ## ----------------------------------------- ## 
    for (p in 2:plays) { 
    choice <- chooseAnArm(p) 
    reward <- rewards.source[p, choice] 

    # Note: When dropping a dim, the methods will be the columns 
    #  and the Outcome info will be the rows. Use `rbind` instead of `cbind`. 
    rewards.received[p,,names(choice)] <- rbind(choice, reward) 

    ## Update the running averages. 
    ## For each method, the current running averages are the same as the 
    ## previous for all arms, except for the one chosen this round. 
    ## Thus start with last round's averages, then update the one arm. 
    running.avgs[p,,] <- running.avgs[p-1,,] 

    # The updating is only involved part (due to lots of array-indexing) 
    running.avgs[p,,][cbind(choice, 1:3)] <- 
    sapply(names(choice), function(m) 
     # Update the running average for the selected arm (for the current play & method) 
      mean(rewards.received[ 1:p,,,drop=FALSE][ rewards.received[1:p,"Arm",m] == choice[m],"Reward",m]) 
    ) 
    } # end for-loop 


    ## DIFFERENT RETURN OPTIONS ## 
    ## ------------------------ ## 


    ## All rewards received, in simplifed matrix (dropping information on arm chosen) 
    # return(rewards.received[, "Reward", ]) 

    ## All rewards received, along with which arm chosen: 
    # return(rewards.received) 

    ## Running averages of the rewards received by method 
    return(apply(rewards.received[, "Reward", ], 2, cumsum)/(1:plays)) 

} 


### EXECUTION (AND SIMULATION) 

## PARAMETERS 
arms <- 10 
plays <- 1000 
epsi1 <- 0.01 
epsi2 <- 0.1 
simuls <- 50 # 2000 
methods=c("greedy", "epsi1", "epsi2") 

## Single Iteration: 
### we can run system time to get an idea for how long one will take 
tme <- system.time(CalculateRewardsPerMethod(arms=arms, epsi1=epsi1, epsi2=epsi2, plays=plays)) 
cat("Expected run time is approx: ", round((simuls * tme[["elapsed"]])/60, 1), " minutes") 

## Multiple iterations (simulations) 
rewards.received.list <- replicate(simuls, CalculateRewardsPerMethod(arms=arms, epsi1=epsi1, epsi2=epsi2, plays=plays), simplify="array") 

## Compute average across simulations 
rewards.received <- apply(rewards.received.list, 1:2, mean) 

## RESULTS 
head(rewards.received, 17) 
MeanRewards <- rewards.received 

## If using an alternate return method in `Calculate..` use the two lines below to calculate running avg 
# CumulRewards <- apply(rewards.received, 2, cumsum) 
# MeanRewards <- CumulRewards/(1:plays) 

## PLOT 
plot.ts(MeanRewards[, "greedy"], col = 'red', lwd = 2, ylim = range(MeanRewards), ylab = 'Average reward', xlab="Plays") 
    lines(MeanRewards[, "epsi1"], col = 'orange', lwd = 2) 
    lines(MeanRewards[, "epsi2"], col = 'navy', lwd = 2) 
    grid(col = 'darkgray') 

    legend('bottomright', c('greedy', paste("epsi1 =", epsi1), paste("epsi2 =", epsi2)), col = c('red', 'orange', 'navy'), lwd = 2, cex = 0.8) 

enter image description here

+0

Lisp'i biliyorsanız, Lisp kodunun burada olduğunu düşünüyorum. : http://webdocs.cs.ualberta.ca/~sutton/book/code/testbed.lisp Belki de R'ye çevrilebilir. R Paketi 'haydut 'yardımcı olabilir, ama bilmiyorum. –

+0

Teşekkürler Mark. Lisp bilmiyorum, ama ben kontrol edeceğim –

+0

Kodunuzu sınayın, güzel görünüyor. Ben güncellemek tek sorun, eps açıldığında açgözlü değeri nasıl 'güncelleme' (% 100 açgözlüdür) 'dir. Diğer durumlarda, tamam çalışıyor. – Fernando

-1

Ayrıca bu bağlantıyı https://www.datahubbs.com/multi_armed_bandits_reinforcement_learning_1/

kontrol etmek isteyebilirsiniz çağrı çalıştırmak için

Yukarıdaki koddan ilgili kodun kopyası O kadar `) (

class eps_bandit: 
''' 
epsilon-greedy k-bandit problem 

Inputs 
===================================================== 
k: number of arms (int) 
eps: probability of random action 0 < eps < 1 (float) 
iters: number of steps (int) 
mu: set the average rewards for each of the k-arms. 
    Set to "random" for the rewards to be selected from 
    a normal distribution with mean = 0. 
    Set to "sequence" for the means to be ordered from 
    0 to k-1. 
    Pass a list or array of length = k for user-defined 
    values. 
''' 

def __init__(self, k, eps, iters, mu='random'): 
    # Number of arms 
    self.k = k 
    # Search probability 
    self.eps = eps 
    # Number of iterations 
    self.iters = iters 
    # Step count 
    self.n = 0 
    # Step count for each arm 
    self.k_n = np.zeros(k) 
    # Total mean reward 
    self.mean_reward = 0 
    self.reward = np.zeros(iters) 
    # Mean reward for each arm 
    self.k_reward = np.zeros(k) 

    if type(mu) == list or type(mu).__module__ == np.__name__: 
     # User-defined averages    
     self.mu = np.array(mu) 
    elif mu == 'random': 
     # Draw means from probability distribution 
     self.mu = np.random.normal(0, 1, k) 
    elif mu == 'sequence': 
     # Increase the mean for each arm by one 
     self.mu = np.linspace(0, k-1, k) 

def pull(self): 
    # Generate random number 
    p = np.random.rand() 
    if self.eps == 0 and self.n == 0: 
     a = np.random.choice(self.k) 
    elif p < self.eps: 
     # Randomly select an action 
     a = np.random.choice(self.k) 
    else: 
     # Take greedy action 
     a = np.argmax(self.k_reward) 

    reward = np.random.normal(self.mu[a], 1) 

    # Update counts 
    self.n += 1 
    self.k_n[a] += 1 

    # Update total 
    self.mean_reward = self.mean_reward + (
     reward - self.mean_reward)/self.n 

    # Update results for a_k 
    self.k_reward[a] = self.k_reward[a] + (
     reward - self.k_reward[a])/self.k_n[a] 

def run(self): 
    for i in range(self.iters): 
     self.pull() 
     self.reward[i] = self.mean_reward 

def reset(self): 
    # Resets results while keeping settings 
    self.n = 0 
    self.k_n = np.zeros(k) 
    self.mean_reward = 0 
    self.reward = np.zeros(iters) 
    self.k_reward = np.zeros(k) 
+0

Bir çözüme bağlantıya açığız, ancak cevabın onsuz yararlı olduğundan emin olun: [bağlantı etrafında bağlam ekle] (// meta.stackexchange.com/a/8259) böylece diğer kullanıcılarınız ne olduğuna dair bir fikre sahip olacaklar. ve neden orada, ardından hedef sayfanın kullanılamaması durumunda linklediğiniz sayfanın en alakalı bölümünü belirtin. [Bir bağlantıdan biraz daha fazla olan cevaplar silinebilir.] (// stackoverflow.com/help/deleted-answers) –

+0

ilgili alıntıları içerecek şekilde düzenlenmiştir –