论文阅读笔记《Spot and Learn: A Maximum-Entropy Patch Sampler for Few-Shot Image Classification》

小样本学习&元学习经典论文整理||持续更新

核心思想

  本文提出一种基于最大熵图块采样算法的强化学习模型来解决小样本学习问题。作者首先提出常见的目标分类网络都是把一整张图片作为输入,进行特征提取,然后分类。而人类在观察事物的时候通常都会把注意力集中在部分感兴趣的区域,也就是所谓的注意力机制,而且当我们第二次看一个物体时,我们的注意力会沿着一定的轨迹移动,也就是说我们每次观察物体的一部分图块,经过多次观察后识别该物体。本文正是利用这一思想,将一幅图片分割成多个图块,组成一个图片序列,依次输入到一个强化学习网络中,经过多次观察后给出分类结果。网络的结构如下图所示
在这里插入图片描述
  每个图块 p i p_i pi都先经过一个图像特征提取网络 f e f_e fe得到对应的特征向量 e i e_i ei,然后与上一阶段的状态输出 s i − 1 s_{i-1} si1和环境信息 c i − 1 c_{i-1} ci1一起进入状态编码器 f s f_s fs,得到当前时刻对应的状态输出 s i s_i si。这一状态有两个用途,一方面作为输入传递到下一时刻的状态编码器,另一方面输入到最大熵图块采样器(Maximum Entropy Sampler)提取下一个阶段的图块 p i + 1 p_{i+1} pi+1。简单点说,这个最大熵图块采样器就是以原图 x x x和当前时刻的状态信息 s i s_i si作为输入,输出下一时刻的动作信息 a i a_i ai(也就是图块的坐标)。但具体来说,最大熵图块采样器由两个部分组成:Q函数 f Q f_Q fQ和采样策略 π θ \pi_{\theta} πθ,其中 f Q f_Q fQ用来评价当前采取动作有多么“好”,而 π θ \pi_{\theta} πθ会输出下一时刻动作信息 a i a_i ai和原图 x x x对应的特征信息 g g g,而这两部分信息又进入动作环境编码器 f a f_{a} fa用于输出当前时刻的环境信息 c i c_i ci。最后经过 N N N次观察之后,输出状态 s N s_N sN并利用分类器 f c f_c fc得到最终的预测类别标签 y ^ \hat{y} y^。整个过程看似复杂,但其实还是比较常规的强化学习流程,问题的难点在于最大熵图块采样器是如何选择出最合适的图块的?
  作者提出了一种基于最大熵的强化学习算法用于输出采样策略,该算法的优化目标如下
在这里插入图片描述
不仅要求最大化回报函数 r t r_t rt,并且在给定状态 s s s的同时最大化策略的熵 H ( π ( ⋅ ∣ s ) ) H(\pi(\cdot|s)) H(π(s)),该问题可采用柔性Q学习的方法来解决
在这里插入图片描述
式中 Q s o f t ( s t , a t ) Q_{soft}(s_t,a_t) Qsoft(st,at)表示Q函数, V s o f t V_{soft} Vsoft表示价值函数,用于评定状态的价值,而最大熵策略如下
在这里插入图片描述
  基于上述的研究,本文提出一种正负样本采样的策略,所谓正样本就是指在感兴趣区域内的图块,而负样本是指背景处的图块。相应的负样本采样策略标识如下
在这里插入图片描述
可以看做是正样本采样策略的相反数。每次正向过程(处理一张图片)都会随机选择是采用正样本采样策略还是负样本采样策略,如果是正样本采样策率则希望分类器输出的预测结果是对应的目标物体,如果是负样本采样策略则希望分类器输出的预测结果是背景,根据这一要求设计了回报函数
在这里插入图片描述
  作者指出采用这一采样策略有双重优势:第一,编码器能够“看到”并学习为错误选择的图块进行编码;第二,这有助于为不同的动作提供不同价值,避免了无论采用何种动作其价值得分都几乎相同的情况。

实现过程

网络结构

  图像特征提取器 f e f_e fe是一个CNN网络,状态编码器 f s f_s fs是一个RNN网络,Q函数 f Q f_Q fQ和采样策略 π θ \pi_{\theta} πθ的结构完全相同,都是一个带有全连接层的小型CNN,动作环境编码器 f a f_a fa和分类器 f c f_c fc结构未介绍。

损失函数

  分类损失根据采取不同的采样策略,计算正负样本对应的损失
在这里插入图片描述
M 1 M_1 M1 M 2 M_2 M2分别表示两种采样模式, j j j表示第 j j j幅图片。图像特征提取器 f e f_e fe,状态编码器 f s f_s fs,动作环境编码器 f a f_a fa和分类器 f c f_c fc利用该损失进行更新。

训练策略

  整个网络的训练过程如下
在这里插入图片描述

创新点

  • 通过将图片分割成图块序列,采用深度强化学习的方式,实现小样本分类任务
  • 设计了最大熵图块采样策略

算法评价

  本文采用深度强化学习的方式实现小样本分类任务,在本质上可以看做是一种基于数据增强的方法,只不过作者是将一幅图片分割成若干个图块,并组成图块序列进行学习。这一方法能够引导网络有针对性的选取图片中有价值的部分进行观察,而不需要在背景区域浪费精力,这在一定程度上提高了模型的学习效率,使得其在少量样本的情况下就能够有效学习分类方法。根据实验结果来看,该算法效果改进不大,但作为一种全新的思路和结构,该算法仍具有进一步研究和改进的价值。

如果大家对于深度学习与计算机视觉领域感兴趣,希望获得更多的知识分享与最新的论文解读,欢迎关注我的个人公众号“深视”。在这里插入图片描述

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是基于Tensorflow的《Soft Actor-Critic: Off-Policy Maximum Entropy Deep Reinforcement Learning with a Stochastic Actor》版本的SAC强化学习算法的Python代码: ```python import tensorflow as tf import numpy as np import gym # Create actor network class Actor(tf.keras.Model): def __init__(self, state_dim, action_dim, max_action): super(Actor, self).__init__() self.layer1 = tf.keras.layers.Dense(256, activation='relu') self.layer2 = tf.keras.layers.Dense(256, activation='relu') self.mu_layer = tf.keras.layers.Dense(action_dim, activation='tanh') self.sigma_layer = tf.keras.layers.Dense(action_dim, activation='softplus') self.max_action = max_action def call(self, state): x = self.layer1(state) x = self.layer2(x) mu = self.mu_layer(x) * self.max_action sigma = self.sigma_layer(x) + 1e-4 return mu, sigma # Create two critic networks class Critic(tf.keras.Model): def __init__(self, state_dim, action_dim): super(Critic, self).__init__() self.layer1 = tf.keras.layers.Dense(256, activation='relu') self.layer2 = tf.keras.layers.Dense(256, activation='relu') self.layer3 = tf.keras.layers.Dense(1, activation=None) def call(self, state, action): x = tf.concat([state, action], axis=1) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) return x # Create Soft Actor-Critic (SAC) Agent class SACAgent: def __init__(self, state_dim, action_dim, max_action): self.actor = Actor(state_dim, action_dim, max_action) self.critic1 = Critic(state_dim, action_dim) self.critic2 = Critic(state_dim, action_dim) self.target_critic1 = Critic(state_dim, action_dim) self.target_critic2 = Critic(state_dim, action_dim) self.max_action = max_action self.alpha = tf.Variable(0.1, dtype=tf.float32, name='alpha') self.gamma = 0.99 self.tau = 0.005 self.optimizer_actor = tf.keras.optimizers.Adam(learning_rate=3e-4) self.optimizer_critic1 = tf.keras.optimizers.Adam(learning_rate=3e-4) self.optimizer_critic2 = tf.keras.optimizers.Adam(learning_rate=3e-4) def get_action(self, state): state = np.expand_dims(state, axis=0) mu, sigma = self.actor(state) dist = tfp.distributions.Normal(mu, sigma) action = tf.squeeze(dist.sample(1), axis=0) return action.numpy() def update(self, replay_buffer, batch_size): states, actions, rewards, next_states, dones = replay_buffer.sample(batch_size) with tf.GradientTape(persistent=True) as tape: # Compute actor loss mu, sigma = self.actor(states) dist = tfp.distributions.Normal(mu, sigma) log_pi = dist.log_prob(actions) q1 = self.critic1(states, actions) q2 = self.critic2(states, actions) q_min = tf.minimum(q1, q2) alpha_loss = -tf.reduce_mean(self.alpha * (log_pi + self.target_entropy)) actor_loss = -tf.reduce_mean(tf.exp(self.alpha) * log_pi * q_min) # Compute critic loss next_mu, next_sigma = self.actor(next_states) next_dist = tfp.distributions.Normal(next_mu, next_sigma) next_actions = tf.clip_by_value(next_dist.sample(1), -self.max_action, self.max_action) target_q1 = self.target_critic1(next_states, next_actions) target_q2 = self.target_critic2(next_states, next_actions) target_q = tf.minimum(target_q1, target_q2) target_q = rewards + self.gamma * (1.0 - dones) * (target_q - tf.exp(self.alpha) * next_dist.entropy()) q1_loss = tf.reduce_mean(tf.square(q1 - target_q)) q2_loss = tf.reduce_mean(tf.square(q2 - target_q)) critic_loss = q1_loss + q2_loss + alpha_loss # Compute gradients and update weights actor_grads = tape.gradient(actor_loss, self.actor.trainable_variables) critic1_grads = tape.gradient(critic_loss, self.critic1.trainable_variables) critic2_grads = tape.gradient(critic_loss, self.critic2.trainable_variables) self.optimizer_actor.apply_gradients(zip(actor_grads, self.actor.trainable_variables)) self.optimizer_critic1.apply_gradients(zip(critic1_grads, self.critic1.trainable_variables)) self.optimizer_critic2.apply_gradients(zip(critic2_grads, self.critic2.trainable_variables)) # Update target networks for w, w_target in zip(self.critic1.weights, self.target_critic1.weights): w_target.assign(self.tau * w + (1 - self.tau) * w_target) for w, w_target in zip(self.critic2.weights, self.target_critic2.weights): w_target.assign(self.tau * w + (1 - self.tau) * w_target) # Update alpha alpha_grad = tape.gradient(alpha_loss, self.alpha) self.alpha.assign_add(1e-4 * alpha_grad) def save(self, filename): self.actor.save_weights(filename + '_actor') self.critic1.save_weights(filename + '_critic1') self.critic2.save_weights(filename + '_critic2') def load(self, filename): self.actor.load_weights(filename + '_actor') self.critic1.load_weights(filename + '_critic1') self.critic2.load_weights(filename + '_critic2') # Create replay buffer class ReplayBuffer: def __init__(self, max_size): self.max_size = max_size self.buffer = [] self.position = 0 def add(self, state, action, reward, next_state, done): if len(self.buffer) < self.max_size: self.buffer.append(None) self.buffer[self.position] = (state, action, reward, next_state, done) self.position = (self.position + 1) % self.max_size def sample(self, batch_size): indices = np.random.choice(len(self.buffer), batch_size, replace=False) states, actions, rewards, next_states, dones = [], [], [], [], [] for idx in indices: state, action, reward, next_state, done = self.buffer[idx] states.append(np.array(state, copy=False)) actions.append(np.array(action, copy=False)) rewards.append(reward) next_states.append(np.array(next_state, copy=False)) dones.append(done) return np.array(states), np.array(actions), np.array(rewards, dtype=np.float32), np.array(next_states), np.array(dones, dtype=np.uint8) # Create environment and agent env = gym.make('Pendulum-v0') state_dim = env.observation_space.shape[0] action_dim = env.action_space.shape[0] max_action = float(env.action_space.high[0]) agent = SACAgent(state_dim, action_dim, max_action) replay_buffer = ReplayBuffer(1000000) # Train agent max_episodes = 1000 max_steps = 500 batch_size = 256 update_interval = 1 target_entropy = -action_dim for episode in range(max_episodes): state = env.reset() total_reward = 0 for step in range(max_steps): action = agent.get_action(state) next_state, reward, done, _ = env.step(action) replay_buffer.add(state, action, reward, next_state, done) if len(replay_buffer.buffer) > batch_size: agent.update(replay_buffer, batch_size) state = next_state total_reward += reward if done: break print("Episode:", episode, "Total Reward:", total_reward) ``` 请注意,以上代码仅供参考,并且需要根据具体环境和参数进行调整和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深视

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值