Bağlamsal haydutlar, öğrencinin en fazla ödülle sonuçlanan eylemleri seçmesi gereken karar verme modellerinde kullanılan bir takviyeli öğrenme algoritmaları sınıfıdır. Adlarını, oyuncunun hangi slot makinelerinde oynayacağına, her makineyi kaç kez oynayacağına ve bunları hangi sırayla oynayacağına karar vermesi gereken klasik "tek kollu haydut" kumar probleminden almıştır.
Bağlamsal haydutları diğerlerinden ayıran şey, karar verme sürecinin bağlam tarafından bilgilendirilmesidir. Bu durumda bağlam, eylemin sonucunu etkileyebilecek bir dizi gözlemlenebilir değişkeni ifade eder. Bu ekleme, haydut sorununu, kararın belirli koşullara bağlı olduğu kişiselleştirilmiş öneriler, klinik araştırmalar veya reklam yerleştirme gibi gerçek dünya uygulamalarına yaklaştırıyor.
Bağlamsal haydut problemi çeşitli algoritmalar kullanılarak uygulanabilir. Aşağıda, bağlamsal haydut sorunlarına yönelik algoritmik yapının üst düzey genel bir özetini sunuyorum:
Ve aşağıdaki algoritma, bağlamsal haydut sorununun altında yatan matematiği gösteriyor:
Yukarıdakilerin hepsini özetlemek gerekirse, genel anlamda algoritmanın amacı, belirli bir zaman diliminde kümülatif ödülü en üst düzeye çıkarmaktır. Her turda yalnızca seçilen eylemin ödülünün gözlemlendiğini unutmayın. Bu, haydut sorunlarını denetimli öğrenmeden ayıran kısmi geri bildirim olarak bilinir.
Bağlamsal bir haydut sorununu çözmek için en yaygın yaklaşım, keşif ve sömürünün dengelenmesini içerir. Kullanım, en iyi kararı vermek için mevcut bilgiyi kullanmak anlamına gelirken keşif, daha fazla bilgi toplamak için daha az kesin eylemde bulunmayı içerir.
Keşif ve kullanım arasındaki denge, Bağlamsal Haydut sorununu çözmek için tasarlanan LinUCB, Neural Bandit veya Decision Tree Bandit gibi çeşitli algoritmalarda kendini gösterir. Bu algoritmaların tümü, bu ödünleşimi ele almak için kendi benzersiz stratejilerini kullanır.
Bu fikrin Bandit için kod temsili şöyledir:
class Bandit: def __init__(self, n_actions, n_features): self.n_actions = n_actions self.n_features = n_features self.theta = np.random.randn(n_actions, n_features) def get_reward(self, action, x): return x @ self.theta[action] + np.random.normal() def get_optimal_reward(self, x): return np.max(x @ self.theta.T) # Usage example # Define the bandit environment n_actions = 10 n_features = 5 bandit = Bandit(n_actions, n_features) # Define the model agent model_agent = model(n_features, *args) # Define the context (features) x = np.random.randn(n_features) # The agent makes a prediction pred_rewards = np.array([model_agent.predict(x) for _ in range(n_actions)]) # The agent chooses an action action = np.argmax(pred_rewards) # The agent gets a reward reward = bandit.get_reward(action, x) # The agent updates its parameters model_agent.update(x, reward)
LinUCB algoritması, bir bağlam verilen bir eylemin beklenen ödülünü doğrusal bir işlev olarak modelleyen bağlamsal bir haydut algoritmasıdır ve keşif ve kullanım arasında denge kurmak için Üst Güven Sınırı (UCB) ilkesine dayalı eylemleri seçer. Mevcut modele göre (doğrusal bir model olan) mevcut en iyi seçeneği kullanır, ancak aynı zamanda modelin tahminlerindeki belirsizliği göz önünde bulundurarak potansiyel olarak daha yüksek ödüller sağlayabilecek seçenekleri de araştırır. Matematiksel olarak şu şekilde sunulabilir:
Bu yaklaşım, algoritmanın yüksek belirsizliğe sahip olduğu eylemleri keşfetmesini sağlar.
Bir eylem seçtikten ve bir ödül aldıktan sonra LinUCB, parametreleri aşağıdaki gibi günceller:
Ve işte Python'daki kod uygulaması:
import numpy as np class LinUCB: def __init__(self, n_actions, n_features, alpha=1.0): self.n_actions = n_actions self.n_features = n_features self.alpha = alpha # Initialize parameters self.A = np.array( [np.identity(n_features) for _ in range(n_actions)] ) # action covariance matrix self.b = np.array( [np.zeros(n_features) for _ in range(n_actions)] ) # action reward vector self.theta = np.array( [np.zeros(n_features) for _ in range(n_actions)] ) # action parameter vector def predict(self, context): context = np.array(context) # Convert list to ndarray context = context.reshape( -1, 1 ) # reshape the context to a single-column matrix p = np.zeros(self.n_actions) for a in range(self.n_actions): theta = np.dot( np.linalg.inv(self.A[a]), self.b[a] ) # theta_a = A_a^-1 * b_a theta = theta.reshape(-1, 1) # Explicitly reshape theta p[a] = np.dot(theta.T, context) + self.alpha * np.sqrt( np.dot(context.T, np.dot(np.linalg.inv(self.A[a]), context)) ) # p_t(a|x_t) = theta_a^T * x_t + alpha * sqrt(x_t^T * A_a^-1 * x_t) return p def update(self, action, context, reward): self.A[action] += np.outer(context, context) # A_a = A_a + x_t * x_t^T self.b[action] += reward * context # b_a = b_a + r_t * x_tx
Karar Ağacı Bandit, ödül fonksiyonunu bir karar ağacı olarak modeller; burada her yaprak düğümü bir eyleme karşılık gelir ve kökten yaprak düğüme giden her yol, bağlama dayalı bir karar kuralını temsil eder. İstatistiksel bir çerçeve aracılığıyla keşif ve kullanım gerçekleştirir, istatistiksel anlamlılık testlerine dayalı olarak karar ağacında bölmeler ve birleştirmeler yapar.
Amaç, beklenen kümülatif ödülü maksimuma çıkaran en iyi karar ağacını öğrenmektir:
Karar ağacı öğrenimi genellikle iki adımdan oluşur:
Bölme kriteri ve birleştirme kriteri genellikle iyileştirmenin istatistiksel anlamlılığını sağlamak için istatistiksel testlere dayalı olarak tanımlanır.
from sklearn.tree import DecisionTreeRegressor class DecisionTreeBandit: def __init__(self, n_actions, n_features, max_depth=5): self.n_actions = n_actions self.n_features = n_features self.max_depth = max_depth # Initialize the decision tree model for each action self.models = [ DecisionTreeRegressor(max_depth=self.max_depth) for _ in range(n_actions) ] self.data = [[] for _ in range(n_actions)] def predict(self, context): return np.array( [self._predict_for_action(a, context) for a in range(self.n_actions)] ) def _predict_for_action(self, action, context): if not self.data[action]: return 0.0 X, y = zip(*self.data[action]) self.models[action].fit(np.array(X), np.array(y)) context_np = np.array(context).reshape( 1, -1 ) # convert list to NumPy array and reshape return self.models[action].predict(context_np)[0] def update(self, action, context, reward): self.data[action].append((context, reward))
DecisionTreeBandit için predict
yöntemi, belirli bir bağlamda her eylem için beklenen ödülü tahmin etmek amacıyla mevcut model parametrelerini kullanır. update
yöntemi, seçilen eylemden gözlemlenen ödüle dayalı olarak model parametrelerini günceller. Bu uygulama DecisionTreeBandit için scikit-learn
kullanıyor.
Yüksek boyutlu veya doğrusal olmayan durumlarda ödül fonksiyonuna yaklaşmak için derin öğrenme modelleri kullanılabilir. Politika tipik olarak bağlamı ve mevcut eylemleri girdi olarak alan ve her eylemin gerçekleştirilme olasılığının çıktısını veren bir sinir ağıdır.
Popüler bir derin öğrenme yaklaşımı, bir ağın (aktör) hangi eylemin gerçekleştirileceğine karar verdiği ve diğer ağın (eleştirmen) aktör tarafından gerçekleştirilen eylemi değerlendirdiği aktör-eleştirmen mimarisini kullanmaktır.
Bağlam ile ödül arasındaki ilişkinin doğrusal olmadığı daha karmaşık senaryolarda ödül fonksiyonunu modellemek için bir sinir ağı kullanabiliriz. Popüler yöntemlerden biri, REINFORCE veya aktör eleştirmeni gibi bir politika gradyanı yöntemi kullanmaktır.
Aşağıdaki özetlemek gerekirse Neural Bandit, sinir ağının parametrelerindeki belirsizliği hesaba katarak ödül fonksiyonunu modellemek için sinir ağlarını kullanır. Ayrıca, politikayı daha yüksek ödüller yönünde güncellediği politika değişimleri aracılığıyla keşif sunar. Bu tür bir keşif daha yönlendirilmiş olup, geniş eylem alanlarında faydalı olabilir.
En basit kod uygulaması şudur:
import torch import torch.nn as nn import torch.optim as optim class NeuralNetwork(nn.Module): def __init__(self, n_features): super(NeuralNetwork, self).__init__() self.layer = nn.Sequential( nn.Linear(n_features, 32), nn.ReLU(), nn.Linear(32, 1) ) def forward(self, x): return self.layer(x) class NeuralBandit: def __init__(self, n_actions, n_features, learning_rate=0.01): self.n_actions = n_actions self.n_features = n_features self.learning_rate = learning_rate # Initialize the neural network model for each action self.models = [NeuralNetwork(n_features) for _ in range(n_actions)] self.optimizers = [ optim.Adam(model.parameters(), lr=self.learning_rate) for model in self.models ] self.criterion = nn.MSELoss() def predict(self, context): context_tensor = torch.tensor(context, dtype=torch.float32) # Convert to tensor with torch.no_grad(): return torch.cat( [model(context_tensor).reshape(1) for model in self.models] ) def update(self, action, context, reward): self.optimizers[action].zero_grad() context_tensor = torch.tensor(context, dtype=torch.float32) # Convert to tensor reward_tensor = torch.tensor(reward, dtype=torch.float32) # Convert to tensor pred_reward = self.models[action](context_tensor) loss = self.criterion(pred_reward, reward_tensor) loss.backward() self.optimizers[action].step()
NeuralBandit için, bir bağlam verilen her eylem için beklenen ödülü tahmin etmek üzere mevcut model parametrelerini kullanan ve seçilen eylemden gözlemlenen ödüle dayalı olarak model parametrelerini güncelleyen, predict
yöntemi ve update
yöntemiyle aynı resim. Bu uygulama NeuralBandit için PyTorch'u kullanıyor.
Her modelin kendine özgü avantajları ve dezavantajları vardır ve model seçimi, eldeki problemin özel gereksinimlerine bağlıdır. Bu modellerden bazılarının özelliklerine bakalım ve ardından performanslarını karşılaştıralım.
Doğrusal Üst Güven Sınırı (LinUCB) modeli, belirli bir bağlamda her eylem için beklenen ödülü tahmin etmek amacıyla doğrusal regresyon kullanır. Ayrıca bu tahminlerin belirsizliğini de takip ediyor ve bunu araştırmayı teşvik etmek için kullanıyor.
Avantajları:
Basit ve hesaplama açısından verimlidir.
Pişmanlık sınırına teorik garantiler sağlar.
Dezavantajları:
Karar Ağacı Haydut modeli, ödül fonksiyonunu bir karar ağacı olarak temsil eder. Her yaprak düğüm bir eyleme karşılık gelir ve kökten yaprak düğüme giden her yol, bağlama dayalı bir karar kuralını temsil eder.
Avantajları:
Yorumlanabilir karar kuralları sağlar.
Karmaşık ödül işlevlerini yerine getirebilir.
Dezavantajları:
Sinir Haydut modeli, belirli bir bağlamda her eylem için beklenen ödülü tahmin etmek için bir sinir ağı kullanır. Keşfi teşvik etmek için politika eğimi yöntemlerini kullanır.
Avantajları:
Karmaşık, doğrusal olmayan ödül fonksiyonlarını yönetebilir.
Geniş aksiyon alanlarında faydalı olan yönlendirilmiş keşif gerçekleştirebilir.
Dezavantajları:
İşte, daha önce bahsedilen ve tanımlanan tüm bu modellerin haydutlarının performanslarını, her model için bir simülasyon çalıştırarak karşılaştırmak için Python kodu.
import matplotlib.pyplot as plt # Define the bandit environment n_actions = 10 n_features = 5 bandit = Bandit(n_actions, n_features) # Define the agents linucb_agent = LinUCB(n_actions, n_features, alpha=0.1) neural_agent = NeuralBandit(n_actions, n_features, learning_rate=0.01) tree_agent = DecisionTreeBandit(n_actions, n_features, max_depth=5) # Run the simulation for each agent n_steps = 1000 agents = [linucb_agent, tree_agent, neural_agent] cumulative_rewards = {agent.__class__.__name__: np.zeros(n_steps) for agent in agents} cumulative_regrets = {agent.__class__.__name__: np.zeros(n_steps) for agent in agents} for agent in agents: print(agent) for t in range(n_steps): x = np.random.randn(n_features) pred_rewards = agent.predict([x]) action = np.argmax(pred_rewards) reward = bandit.get_reward(action, x) optimal_reward = bandit.get_optimal_reward(x) agent.update(action, x, reward) cumulative_rewards[agent.__class__.__name__][t] = ( reward if t == 0 else cumulative_rewards[agent.__class__.__name__][t - 1] + reward ) cumulative_regrets[agent.__class__.__name__][t] = ( optimal_reward - reward if t == 0 else cumulative_regrets[agent.__class__.__name__][t - 1] + optimal_reward - reward ) # Plot the results plt.figure(figsize=(12, 6)) plt.subplot(121) for agent_name, rewards in cumulative_rewards.items(): plt.plot(rewards, label=agent_name) plt.xlabel("Steps") plt.ylabel("Cumulative Rewards") plt.legend() plt.subplot(122) for agent_name, regrets in cumulative_regrets.items(): plt.plot(regrets, label=agent_name) plt.xlabel("Steps") plt.ylabel("Cumulative Regrets") plt.legend() plt.show()
Bu uygulamaların her birinde, keşif ve kullanım arasında denge kurmak çok önemlidir. Kullanım, mevcut bilgiye dayanarak en iyi eylemi seçmektir, keşif ise daha fazla bilgi edinmek için farklı eylemleri denemektir. Bağlamsal haydut algoritmaları, bu keşif-sömürü değiş tokuşunu resmileştirmek ve çözmek için bir çerçeve sağlar.
Bağlamsal haydutlar, geri bildirimin sınırlı olduğu ortamlarda karar vermede güçlü bir araçtır. Karar vermede bağlamı kullanma yeteneği, geleneksel haydut algoritmalarından daha karmaşık ve incelikli kararlara olanak tanır.
Performansı açık bir şekilde karşılaştırmasak da algoritma seçiminin problem özelliklerinden etkilenmesi gerektiğini belirttik. Daha basit ilişkiler için LinUCB ve Karar Ağaçları üstün olabilirken Sinir Ağları karmaşık senaryolarda daha iyi performans gösterebilir. Her yöntem benzersiz güçlü yönler sunuyordu: Matematiksel basitliği nedeniyle LinUCB, yorumlanabilirliği nedeniyle Karar Ağaçları ve karmaşık ilişkileri ele alma becerileri nedeniyle Sinir Ağları. Doğru yaklaşımı seçmek, bu heyecan verici alanda etkili problem çözmenin anahtarıdır.
Genel olarak, bağlama dayalı haydut sorunları, takviyeli öğrenme kapsamında ilgi çekici bir alan sunar; bunların üstesinden gelmek için çeşitli algoritmalar mevcuttur ve bu güçlü modellerin daha da yenilikçi kullanımlarını görmeyi bekleyebiliriz.