Skip to content

Latest commit

 

History

History
783 lines (502 loc) · 30.3 KB

File metadata and controls

783 lines (502 loc) · 30.3 KB

七、元 SGD 和 Reptile

在上一章中,我们学习了如何使用 MAML 查找可在多个任务中推广的最佳参数。 我们看到了 MAML 如何通过计算元梯度和执行元优化来计算此最佳参数。 我们还看到了对抗性元学习,它通过添加对抗性样本并使 MAML 在干净样本和对抗性样本之间进行搏斗以找到最佳参数,从而增强了 MAML。 我们还看到了 CAML,或者说是元学习的上下文适应。 在本章中,我们将学习元 SGD,这是另一种用于快速执行学习的元学习算法。 与 MAML 不同,元 SGD 不仅会找到最佳参数,还将找到最佳学习率和更新方向。 我们将看到如何在监督学习和强化学习设置中使用元 SGD。 我们还将看到如何从头开始构建元 SGD。 继续,我们将学习 Reptile 算法,该算法对 MAML 进行了改进。 我们将看到 Reptile 与 MAML 有何不同,然后将介绍如何在正弦波回归任务中使用 Reptile。

在本章中,您将了解以下内容:

  • 元 SGD
  • 监督学习中的元 SGD
  • 强化学习中的元 SGD
  • 从头开始构建元 SGD
  • Reptile
  • 将 Reptile 用于正弦波回归

元 SGD

假设我们有一些任务T。 我们使用通过某些参数θ参数化的模型f,并训练模型以最大程度地减少损失。 我们使用梯度下降使损失最小化,并找到模型的最佳参数θ'[i]

让我们回想一下梯度下降的更新规则:

那么,构成梯度下降的关键因素是什么? 让我们来看看:

  • 参数θ
  • 学习率α
  • 更新方向

我们通常将参数θ设置为某个随机值,并在训练过程中尝试找到最佳值,然后将学习率α的值设置为一个小数值,或者将其随时间衰减,以及跟随梯度的更新方向。 我们是否可以通过元学习来学习梯度下降的所有这些关键特征,以便可以从几个数据点快速学习? 在上一章中,我们已经看到 MAML 如何找到可在各个任务之间推广的最佳初始参数θ。 有了最佳的初始参数,我们就可以减少梯度步骤,并快速学习新任务。

因此,现在我们是否可以学习最佳的学习率和更新方向,从而可以跨任务进行概括,从而实现更快的收敛和训练? 让我们看看如何通过将其与 MAML 进行比较在元 SGD 中学习。 如果您还记得,请在 MAML 内循环中,通过最小化梯度下降带来的损失,找到每个任务T[i]的最佳参数θ'[i]

对于元 SGD,我们可以按如下方式重写前面的公式:

但是有什么区别呢? 此处α不仅是一个标量小值,而且是一个向量。 我们以与θ相同的形状随机初始化α。我们将θ称为初始参数,将αᐁ[θ]L[T[i]](f[θ])称为自适应项。 因此,自适应项表示更新方向,其长度成为学习率。 我们在自适应项的方向而不是在梯度方向ᐁ[θ]L[T[i]](f[θ])上更新我们的值,并且在自适应项中隐式地实现了我们的学习率。

因此,在元 SGD 中,我们不会使用较小的标量值来初始化学习率α。 相反,我们使用与θ相同形状的随机值来初始化学习率,并与θ一起学习它们。 我们采样了一些任务,并且对于每个任务,我们采样了一些k数据点,并使用梯度下降使损失最小化,但是我们的更新方程式变为:

也就是说,我们的更新方向是自适应项方向,而不是梯度方向,并且我们将αθ一起学习。

现在,在外循环中,我们执行元优化-也就是说,我们计算相对于最佳参数θ'[i]的损失梯度,并更新我们随机初始化的模型参数θ。 在元 SGD 中,我们还更新了随机初始化的α,而不是单独更新θ,如下所示:

如您所见,元 SGD 只是对 MAML 的一小部分调整。 在 MAML 中,我们随机初始化模型参数θ,并尝试找到可跨任务通用的最佳参数。 在元 SGD 中,我们不仅学习模型参数θ,还学习了学习率和更新方向,这在适应性项中隐含地实现。

用于监督学习的元 SGD

现在,我们将看到如何在有监督的学习环境中使用元 SGD。 与 MAML 一样,我们可以将元 SGD 应用于可以通过梯度下降训练的任何监督学习问题,无论是回归学习还是分类学习。 首先,我们需要定义我们要使用的损失函数。 例如,如果要执行分类,则可以使用交叉熵作为损失函数,如果要进行回归,则可以使用均方误差作为损失函数。 我们可以使用适合我们任务的任何损失函数。 让我们逐步进行以下操作:

  1. 假设我们有一个由参数θ参数化的模型f,并且在任务!p(T)上有一个分布。 首先,我们随机初始化模型参数θ,并随机初始化α形状与θ相同的形状。

  2. 我们从任务分布中抽样一些任务T[i]T[i] ~ p(T)。 假设我们已经采样了三个任务,然后是T = {T[1]m T[2], T[3]}

  3. 内循环:对于任务(T)中的每个任务(T[i]),我们对k数据点进行采样,并准备训练和测试数据集:

现在,我们在D_train[i]上应用了一种监督学习算法,使用梯度下降法计算并最小化了损失,并获得了最佳参数θ'[i]

因此,对于每个任务,我们对k个数据点进行采样,并最大程度地减少训练集D_train[i]上的损失,并获得最佳参数θ'[i]。 当我们采样三个任务时,我们将拥有三个最佳参数θ'[i]

  1. 外循环:现在,我们在测试集(元训练集)中执行元优化-也就是说,在这里,我们尝试使测试集D_test[i]中的损失最小化。 通过计算相对于上一步中计算出的最佳参数θ'[i]的梯度,我们将损失降至最低,并使用测试集更新随机初始化的参数θ。 我们不仅更新θ,还更新我们的随机初始化参数α,它可以表示为:

  1. 对于n次迭代,我们重复步骤 2 到步骤 4。

从头开始构建元 SGD

在上一节中,我们了解了元 SGD 的工作原理。 我们看到了元 SGD 如何获得更好,更健壮的模型参数θ,该参数可跨任务进行通用化,并具有最佳的学习率和更新方向。 现在,我们将从头开始对元 SGD 进行编码,以更好地了解它们。 就像我们在 MAML 中所做的一样,为了更好地理解,我们将考虑一个简单的二分类任务。 我们随机生成输入数据,并使用简单的单层神经网络对其进行训练,并尝试找到最佳参数θ'[i]。 我们将逐步详细介绍如何执行此操作。

您还可以在此处查看 Jupyter 笔记本中提供的代码,并提供说明

首先,我们导入numpy库:

import numpy as np

生成数据点

现在,我们定义了一个名为sample_points的函数,用于生成输入(x, y)对。 它以参数k作为输入,这意味着我们要采样的(x, y)对的数量:

def sample_points(k):
    x = np.random.rand(k,50)
    y = np.random.choice([0, 1], size=k, p=[.5, .5]).reshape([-1,1])
    return x,y

前面的函数返回的输出如下:

x, y = sample_points(10)
print x[0]
print y[0]

[5.01913307e-01 1.01874941e-01 7.16678998e-01 3.90294047e-01
 2.95330904e-01 8.66751993e-01 5.09988127e-01 8.59389493e-01
 5.16202142e-01 7.92016358e-01 8.24237307e-01 7.76739141e-01
 8.57034917e-01 2.75862141e-01 6.44874856e-01 2.75248940e-01
 5.67665047e-01 9.61564994e-01 7.58931873e-01 1.08989614e-02
 7.69325529e-01 4.05955016e-01 1.98799935e-01 9.94134622e-01
 3.07179216e-01 1.34756367e-01 2.92326855e-01 5.00026528e-01
 7.23673231e-01 5.28698231e-01 1.52495715e-01 9.20139339e-01
 1.76127500e-02 2.42244262e-01 7.09515862e-01 7.10358091e-01
 6.47656449e-01 5.15623266e-01 8.77002211e-01 4.18744855e-01
 9.67902538e-01 8.79261670e-01 5.88524781e-01 5.11397703e-02
 7.07513737e-01 4.61998029e-01 8.77306226e-01 5.32049083e-01
 8.07178697e-01 5.01521846e-04]
[1]

单层神经网络

我们使用只有一层的神经网络来预测输出:

a = np.matmul(X, theta)
YHat = sigmoid(a)

因此,我们使用元 SGD 查找最佳参数值theta,学习率和梯度更新方向,这些方向可在各个任务之间推广。 因此,对于一项新任务,我们可以通过采取较少的梯度步骤,在较短的时间内从几个数据点中学习。

元 SGD

现在,我们定义一个名为MetaSGD的类,在其中实现元 SGD 算法。 在__init__方法中,我们将初始化所有必需的变量。 然后,我们定义 Sigmoid 激活函数。 之后,我们定义训练函数:

class MetaSGD(object):

我们定义__init__方法并初始化所有必需的变量:

    def __init__(self):

        #initialize number of tasks i.e number of tasks we need in each batch of tasks
        self.num_tasks = 2

        #number of samples i.e number of shots -number of data points (k) we need to have in each task
        self.num_samples = 10

        #number of epochs i.e training iterations
        self.epochs = 10000

        #hyperparameter for the outer loop (outer gradient update) i.e meta optimization
        self.beta = 0.0001

        #randomly initialize our model parameter theta
        self.theta = np.random.normal(size=50).reshape(50, 1)

        #randomly initialize alpha with same shape as theta
        self.alpha = np.random.normal(size=50).reshape(50, 1)

我们定义了sigmoid激活函数:

    def sigmoid(self,a):
        return 1.0 / (1 + np.exp(-a))

现在,让我们开始训练:

    def train(self):

对于周期数:

        for e in range(self.epochs): 

            self.theta_ = []

对于一批任务中的i任务:

           for i in range(self.num_tasks):

我们对k个数据点进行采样,并准备训练集:

                XTrain, YTrain = sample_points(self.num_samples)

然后,我们使用单层网络预测y的值:

                a = np.matmul(XTrain, self.theta)

                YHat = self.sigmoid(a)

我们计算损失并计算梯度:

                #since we're performing classification, we use cross entropy loss as our loss function
                loss = ((np.matmul(-YTrain.T, np.log(YHat)) - np.matmul((1 -YTrain.T), np.log(1 - YHat)))/self.num_samples)[0][0]

                #minimize the loss by calculating gradients
                gradient = np.matmul(XTrain.T, (YHat - YTrain)) / self.num_samples

之后,我们更新梯度并为每个任务找到最佳参数θ'[i]

                self.theta_.append(self.theta - (np.multiply(self.alpha,gradient)))

我们初始化元梯度:

            meta_gradient = np.zeros(self.theta.shape)

            for i in range(self.num_tasks):

我们对k个数据点进行采样,并准备用于元训练D_test[i]的测试集:

                XTest, YTest = sample_points(10)

然后,我们预测y的值:

                a = np.matmul(XTest, self.theta_[i])

                YPred = self.sigmoid(a)

我们计算元梯度:

                meta_gradient += np.matmul(XTest.T, (YPred - YTest)) / self.num_samples

现在,我们更新模型参数thetaalpha

            self.theta = self.theta-self.beta*meta_gradient/self.num_tasks

            self.alpha = self.alpha-self.beta*meta_gradient/self.num_tasks 

我们每 1000 个周期打印一次损失:

            if e%1000==0:
                print "Epoch {}: Loss {}\n".format(e,loss) 
                print 'Updated Model Parameter Theta\n'
                print 'Sampling Next Batch of Tasks \n'
                print '---------------------------------\n'

MetaSGD的完整代码如下:

class MetaSGD(object):
    def __init__(self):

        #initialize number of tasks i.e number of tasks we need in each batch of tasks
        self.num_tasks = 2

        #number of samples i.e number of shots -number of data points (k) we need to have in each task
        self.num_samples = 10

        #number of epochs i.e training iterations
        self.epochs = 10000

        #hyperparameter for the inner loop (inner gradient update)
        self.alpha = 0.0001

        #hyperparameter for the outer loop (outer gradient update) i.e meta optimization
        self.beta = 0.0001

        #randomly initialize our model parameter theta
        self.theta = np.random.normal(size=50).reshape(50, 1)

        #randomly initialize alpha with same shape as theta
        self.alpha = np.random.normal(size=50).reshape(50, 1)

    #define our sigmoid activation function 
    def sigmoid(self,a):
        return 1.0 / (1 + np.exp(-a))

    #now let's get to the interesting part i.e training :P
    def train(self):

        #for the number of epochs,
        for e in range(self.epochs): 

            self.theta_ = []

            #for task i in batch of tasks
            for i in range(self.num_tasks):

                #sample k data points and prepare our train set
                XTrain, YTrain = sample_points(self.num_samples)

                a = np.matmul(XTrain, self.theta)

                YHat = self.sigmoid(a)

                #since we're performing classification, we use cross entropy loss as our loss function
                loss = ((np.matmul(-YTrain.T, np.log(YHat)) - np.matmul((1 -YTrain.T), np.log(1 - YHat)))/self.num_samples)[0][0]

                #minimize the loss by calculating gradients
                gradient = np.matmul(XTrain.T, (YHat - YTrain)) / self.num_samples

                #update the gradients and find the optimal parameter theta' for each of tasks
                self.theta_.append(self.theta - (np.multiply(self.alpha,gradient)))

            #initialize meta gradients
            meta_gradient = np.zeros(self.theta.shape)

            for i in range(self.num_tasks):

                #sample k data points and prepare our test set for meta training
                XTest, YTest = sample_points(10)

                #predict the value of y
                a = np.matmul(XTest, self.theta_[i])

                YPred = self.sigmoid(a)

                #compute meta gradients
                meta_gradient += np.matmul(XTest.T, (YPred - YTest)) / self.num_samples

            #update our randomly initialized model parameter theta with the meta gradients
            self.theta = self.theta-self.beta*meta_gradient/self.num_tasks

            #update our randomly initialized hyperparameter alpha with the meta gradients
            self.alpha = self.alpha-self.beta*meta_gradient/self.num_tasks

            if e%1000==0:
                print "Epoch {}: Loss {}\n".format(e,loss) 
                print 'Updated Model Parameter Theta\n'
                print 'Sampling Next Batch of Tasks \n'
                print '---------------------------------\n'

我们创建MetaSGD类的实例:

model = MetaSGD()

让我们开始训练模型:

model.train()

您可以通过各种周期看到损失如何最小化:

Epoch 0: Loss 2.22523195333

Updated Model Parameter Theta

Sampling Next Batch of Tasks 

---------------------------------

Epoch 1000: Loss 1.951785305709

Updated Model Parameter Theta

Sampling Next Batch of Tasks 

---------------------------------

Epoch 2000: Loss 1.47382270343

Updated Model Parameter Theta

Sampling Next Batch of Tasks 

---------------------------------

Epoch 3000: Loss 1.07296354822

Updated Model Parameter Theta

Sampling Next Batch of Tasks 

---------------------------------

#元 SGD 用于强化学习

现在,我们将了解如何在强化学习中使用元 SGD。元 SGD 与可以通过梯度下降训练的任何 RL 算法兼容。

  1. 假设我们有一个由参数θ参数化的模型f,并且在任务p(T)上有一个分布。 首先,我们随机初始化模型参数θ,并随机初始化形状与θ相同的α
  2. 从任务分布中采样一些任务T[i]T[i] ~ p(T)。 假设我们已经采样了三个任务T = {T[1], T[2], T[3]}
  3. 内循环:对于任务(T)中的每个任务(T[i]),我们对D_train[i]轨迹进行采样,使用梯度下降计算损失并将损失最小化,并获得最佳参数θ'[i]。因此,对于每个任务,我们都对轨迹进行采样,最大程度地减少损失并获得最佳参数θ'[i]。 当我们采样三个任务时,对于所有三个任务,我们将拥有三个最佳参数θ'[i]。 接下来,我们将对另一组称为D_test[i]的轨迹进行元更新。
  4. 外循环:现在,我们在D_test[i]轨迹中执行元优化。 我们通过计算相对于上一步获得的最佳参数θ'[i]的梯度,更新我们随机初始化的参数θα来使损失最小化:

  1. 对于n次迭代,我们重复步骤 2 到步骤 4。

Reptile

Reptile 算法已被 OpenAI 提出作为对 MAML 的改进。 它很容易实现。 我们知道,在 MAML 中,我们可以计算二阶导数,即梯度的梯度。 但是从计算上来说,这不是一个有效的任务。 因此,OpenAI 提出了对 MAML 的改进,称为 Reptile。 Reptile 的算法非常简单。 对一些n个任务进行采样,然后运行随机梯度下降SGD),以减少每个采样任务的迭代次数,然后沿某个方向更新模型参数,这是所有任务的共同点。 由于我们对每个任务执行的 SGD 迭代次数较少,因此间接暗示我们正在计算损失的二阶导数。 与 MAML 不同,它在计算上很有效,因为我们不直接计算二阶导数也不展开计算图,因此易于实现。

假设我们从任务分布中采样了两个任务T[1]T[2],并随机初始化了模型参数θ。 首先,我们接受任务T[1]并对某些n次迭代执行 SGD,并获得最佳参数θ'[i]。 然后我们执行下一个任务T[2],迭代执行 SGD n次,并获得最佳参数θ'[i]。 因此,我们有两个最佳参数集:θ' = {θ'[1], θ'[2]}。 现在,我们需要沿更靠近这两个最佳参数的方向移动参数θ,如下图所示:

但是,如何在更接近最佳参数θ'[i]的方向上移动随机初始化的模型参数θ呢? 首先,我们需要找到随机初始化的模型参数θ与最佳参数集θ'之间的距离。 因此,我们使用欧几里得距离D作为找到该距离的距离度量。 找到θθ'之间的距离后,我们需要将它们最小化:

最小化θθ'之间的距离实际上会将我们随机初始化的模型参数θ移向更接近最佳参数θ'[i]的方向。 但是我们如何才能最小化这个距离呢? 我们基本上计算距离ᐁ[θ]E[1/2 D(θ, θ')^2]的梯度以将其最小化,它可以编写如下:

因此,在计算了梯度之后,我们的最终更新方程变为:

通过使用先前的方程式更新模型参数θ,我们实质上使初始参数θ与最佳参数值θ'之间的距离最小。 因此,我们通过执行n次迭代的 SGD,找到每个任务的最佳参数。 一旦获得了最佳参数集,就可以使用先前的公式更新模型参数θ

Reptile 算法

Reptile 是一种简单而有效的算法。 Reptile 可以实现串行和批量版本。 在串行版本中,我们仅从任务分发中抽样一个任务,而在批量版本中,我们对一批任务进行抽样并尝试找到最佳参数。 我们将看到 Reptile 的串行版本如何工作。 Reptile 所涉及的步骤顺序如下:

  1. 假设我们有任务的分布p(T),并且我们随机初始化模型参数θ
  2. 现在我们从任务分布T ~ p(T)中抽取任务T
  3. 对于采样的任务T,我们对k个数据点进行采样,并准备我们的数据集DD = {(x1, y1), (x2, y2), 。.., (xk, yk)}。 我们的数据集基本上包含x特征和y标签。 现在,我们通过对某些n迭代次数执行随机梯度下降来最大程度地减少数据集中的损失。 在对采样任务T,执行n次迭代的 SGD 之后,我们将获得最佳参数θ'[i]
  4. 我们在更接近先前步骤中获得的最佳参数θ'[i]的方向上更新了随机初始化的参数θ如下:θ = θ + ε(θ - θ')
  5. 对于n迭代次数,我们重复步骤 2 到步骤 4。

将 Reptile 用于正弦波回归

在上一节中,我们了解了 Reptile 的工作原理。 现在,我们将从头开始对 Reptile 进行编码,从而更好地理解它。 假设我们有一个任务集合,每个任务的目标是在给定一些输入的情况下使正弦波的输出回归。 那是什么意思呢?

假设y = amplitude * sin(x + phase)。 我们算法的目标是学习在给定x的情况下对y的值进行回归。 幅度的值在 0.1 到 5.0 之间随机选择,相位的值在 0 到π之间随机选择。 因此,对于每个任务,我们仅采样 10 个数据点并训练网络-也就是说,对于每个任务,我们仅采样 10 个(x, y)对。 让我们看一下代码并详细查看它。

您还可以在此处查看 Jupyter 笔记本中提供的代码,并提供说明

首先,我们导入所有必需的库:

import tensorflow as tf
import numpy as np

生成数据点

现在,我们定义了一个称为sample_points的函数,用于生成(x, y)对。 它以参数k作为输入,这意味着我们要采样的(x, y)对的数量:

def sample_points(k):

    num_points = 100

    #amplitude
    amplitude = np.random.uniform(low=0.1, high=5.0)

    #phase
    phase = np.random.uniform(low=0, high=np.pi)

    x = np.linspace(-5, 5, num_points)

    #y = a*sin(x+b)
    y = amplitude * np.sin(x + phase)

    #sample k data points
    sample = np.random.choice(np.arange(num_points), size=k)

    return (x[sample], y[sample])

两层神经网络

像 MAML 一样,Reptile 也与可以通过梯度下降训练的任何算法兼容。 因此,我们使用具有 64 个隐藏单元的简单两层神经网络。

首先,让我们重置 TensorFlow 图:

tf.reset_default_graph()

我们初始化网络参数:

num_hidden = 64
num_classes = 1
num_feature = 1

接下来,我们为输入和输出定义占位符:

X = tf.placeholder(tf.float32, shape=[None, num_feature])
Y = tf.placeholder(tf.float32, shape=[None, num_classes])

我们随机初始化模型参数:

w1 = tf.Variable(tf.random_uniform([num_feature, num_hidden]))
b1 = tf.Variable(tf.random_uniform([num_hidden]))

w2 = tf.Variable(tf.random_uniform([num_hidden, num_classes]))
b2 = tf.Variable(tf.random_uniform([num_classes]))

然后,我们执行前馈操作以预测输出Yhat

#layer 1
z1 = tf.matmul(X, w1) + b1
a1 = tf.nn.tanh(z1)

#output layer
z2 = tf.matmul(a1, w2) + b2
Yhat = tf.nn.tanh(z2)

我们使用均方误差作为损失函数:

loss_function = tf.reduce_mean(tf.square(Yhat - Y))

然后,我们使用 Adam 优化器将损失降至最低:

optimizer = tf.train.AdamOptimizer(1e-2).minimize(loss_function)

我们初始化 TensorFlow 变量:

init = tf.global_variables_initializer()

Reptile

现在,我们将看到如何使用 Reptile 找到神经网络的最佳参数。

首先,我们初始化必要的变量:

#number of epochs i.e training iterations
num_epochs = 100

#number of samples i.e number of shots
num_samples = 50 

#number of tasks
num_tasks = 2

#number of times we want to perform optimization
num_iterations = 10

#mini btach size
mini_batch = 10 

然后,我们开始 TensorFlow 会话:

with tf.Session() as sess:

    sess.run(init)

对于周期数:

    for e in range(num_epochs):

        #for each task in batch of tasks
        for task in range(num_tasks):

我们得到模型的初始参数:

            old_w1, old_b1, old_w2, old_b2 = sess.run([w1, b1, w2, b2,])

然后,我们对xy进行采样:

            x_sample, y_sample = sample_points(num_samples)

对于某些k迭代,我们对任务执行优化:

            for k in range(num_iterations):

                #get the minibatch x and y
                for i in range(0, num_samples, mini_batch):

                    #sample mini batch of examples 
                    x_minibatch = x_sample[i:i+mini_batch]
                    y_minibatch = y_sample[i:i+mini_batch]

                    train = sess.run(optimizer, feed_dict={X: x_minibatch.reshape(mini_batch,1), 
                                                           Y: y_minibatch.reshape(mini_batch,1)})

经过几次优化迭代后,我们获得了更新的模型参数:

            new_w1, new_b1, new_w2, new_b2 = sess.run([w1, b1, w2, b2])

现在,我们执行元更新:

            epsilon = 0.1

            updated_w1 = old_w1 + epsilon * (new_w1 - old_w1) 
            updated_b1 = old_b1 + epsilon * (new_b1 - old_b1) 

            updated_w2 = old_w2 + epsilon * (new_w2 - old_w2) 
            updated_b2 = old_b2 + epsilon * (new_b2 - old_b2) 

我们使用新参数更新模型参数:

            w1.load(updated_w1, sess)
            b1.load(updated_b1, sess)

            w2.load(updated_w2, sess)
            b2.load(updated_b2, sess)

然后,我们每 10 个周期打印一次损失:

        if e%10 == 0:
            loss = sess.run(loss_function, feed_dict={X: x_sample.reshape(num_samples,1), Y: y_sample.reshape(num_samples,1)})

            print "Epoch {}: Loss {}\n".format(e,loss) 
            print 'Updated Model Parameter Theta\n'
            print 'Sampling Next Batch of Tasks \n'
            print '---------------------------------\n'

完整的代码如下:

#start the tensorflow session
with tf.Session() as sess:

    sess.run(init)

    for e in range(num_epochs):

        #for each task in batch of tasks
        for task in range(num_tasks):

            #get the initial parameters of the model
            old_w1, old_b1, old_w2, old_b2 = sess.run([w1, b1, w2, b2,])

            #sample x and y
            x_sample, y_sample = sample_points(num_samples)

            #for some k number of iterations perform optimization on the task
            for k in range(num_iterations):

                #get the minibatch x and y
                for i in range(0, num_samples, mini_batch):

                    #sample mini batch of examples 
                    x_minibatch = x_sample[i:i+mini_batch]
                    y_minibatch = y_sample[i:i+mini_batch]

                    train = sess.run(optimizer, feed_dict={X: x_minibatch.reshape(mini_batch,1), 
                                                           Y: y_minibatch.reshape(mini_batch,1)})

            #get the updated model parameters after several iterations of optimization
            new_w1, new_b1, new_w2, new_b2 = sess.run([w1, b1, w2, b2])

            #Now we perform meta update

            #i.e theta = theta + epsilon * (theta_star - theta)

            epsilon = 0.1

            updated_w1 = old_w1 + epsilon * (new_w1 - old_w1) 
            updated_b1 = old_b1 + epsilon * (new_b1 - old_b1) 

            updated_w2 = old_w2 + epsilon * (new_w2 - old_w2) 
            updated_b2 = old_b2 + epsilon * (new_b2 - old_b2) 

            #update the model parameter with new parameters
            w1.load(updated_w1, sess)
            b1.load(updated_b1, sess)

            w2.load(updated_w2, sess)
            b2.load(updated_b2, sess)

        if e%10 == 0:
            loss = sess.run(loss_function, feed_dict={X: x_sample.reshape(num_samples,1), Y: y_sample.reshape(num_samples,1)})

            print "Epoch {}: Loss {}\n".format(e,loss) 
            print 'Updated Model Parameter Theta\n'
            print 'Sampling Next Batch of Tasks \n'
            print '---------------------------------\n'

您可以看到如下输出:

Epoch 0: Loss 13.0675544739

Updated Model Parameter Theta

Sampling Next Batch of Tasks 

---------------------------------

Epoch 10: Loss 7.3604927063

Updated Model Parameter Theta

Sampling Next Batch of Tasks 

---------------------------------

Epoch 20: Loss 4.35141277313

Updated Model Parameter Theta

Sampling Next Batch of Tasks 

---------------------------------

总结

在本章中,我们学习了元 SGD 和 Reptile 算法。 我们看到了元 SGD 与 MAML 有何不同,以及如何在监督学习和强化学习设置中使用元 SGD。 我们看到了元 SGD 如何学习模型参数以及学习率和更新方向。 我们还了解了如何从头开始构建元 SGD。 然后,我们了解了 Reptile 算法。 我们看到了 Reptile 与 MAML 的不同之处,以及 Reptile 对 MAML 算法的改进。 我们还学习了如何在正弦波回归任务中使用 Reptile。

在下一章中,我们将学习如何将梯度一致性用作元学习中的优化目标。

问题

  1. 元 SGD 与 MAML 有何不同?
  2. 元 SGD 如何找到最佳学习率?
  3. 元 SGD 中学习率的更新方程是什么?
  4. Reptile 算法如何工作?
  5. Reptile 算法的更新方程是什么?

进一步阅读