持续学习EWC

EWC代码

持续学习相关代码可前往此处下载:ewc等算法完整实现

以下为ewc算法的pytorch实现

ewc.py代码

import sys, time
import numpy as np
import torch
from copy import deepcopy

import utils


class Appr(object):
    """ Class implementing the Elastic Weight Consolidation approach described in http://arxiv.org/abs/1612.00796 """

    def __init__(self, model, nepochs=100, sbatch=64, lr=0.05, lr_min=1e-4, lr_factor=3, lr_patience=5, clipgrad=100,
                 lamb=5000, args=None):
        self.model = model
        self.model_old = None
        self.fisher = None

        self.nepochs = nepochs
        self.sbatch = sbatch
        self.lr = lr
        self.lr_min = lr_min
        self.lr_factor = lr_factor
        self.lr_patience = lr_patience
        self.clipgrad = clipgrad

        self.ce = torch.nn.CrossEntropyLoss()
        self.optimizer = self._get_optimizer()
        self.lamb = lamb  # Grid search = [500,1000,2000,5000,10000,20000,50000]; best was 5000
        if len(args.parameter) >= 1:
            params = args.parameter.split(',')
            print('Setting parameters to', params)
            self.lamb = float(params[0])

        return

    def _get_optimizer(self, lr=None):
        if lr is None: lr = self.lr
        return torch.optim.SGD(self.model.parameters(), lr=lr)

    def train(self, t, xtrain, ytrain, xvalid, yvalid):
        best_loss = np.inf
        best_model = utils.get_model(self.model)
        lr = self.lr
        patience = self.lr_patience
        self.optimizer = self._get_optimizer(lr)

        # Loop epochs
        for e in range(self.nepochs):
            # Train
            clock0 = time.time()
            self.train_epoch(t, xtrain, ytrain)
            clock1 = time.time()
            train_loss, train_acc = self.eval(t, xtrain, ytrain)
            clock2 = time.time()
            print('| Epoch {:3d}, time={:5.1f}ms/{:5.1f}ms | Train: loss={:.3f}, acc={:5.1f}% |'.format(
                e + 1, 1000 * self.sbatch * (clock1 - clock0) / xtrain.size(0),
                1000 * self.sbatch * (clock2 - clock1) / xtrain.size(0), train_loss, 100 * train_acc), end='')
            # Valid
            valid_loss, valid_acc = self.eval(t, xvalid, yvalid)
            print(' Valid: loss={:.3f}, acc={:5.1f}% |'.format(valid_loss, 100 * valid_acc), end='')
            # Adapt lr
            if valid_loss < best_loss:
                best_loss = valid_loss
                best_model = utils.get_model(self.model)
                patience = self.lr_patience
                print(' *', end='')
            else:
                patience -= 1
                if patience <= 0:
                    lr /= self.lr_factor
                    print(' lr={:.1e}'.format(lr), end='')
                    if lr < self.lr_min:
                        print()
                        break
                    patience = self.lr_patience
                    self.optimizer = self._get_optimizer(lr)
            print()

        # Restore best
        utils.set_model_(self.model, best_model)

        # Update old
        self.model_old = deepcopy(self.model)
        self.model_old.eval()
        utils.freeze_model(self.model_old)  # Freeze the weights

        # Fisher ops
        if t > 0:
            fisher_old = {}
            for n, _ in self.model.named_parameters():
                fisher_old[n] = self.fisher[n].clone()
        self.fisher = utils.fisher_matrix_diag(t, xtrain, ytrain, self.model, self.criterion)
        if t > 0:
            # Watch out! We do not want to keep t models (or fisher diagonals) in memory, therefore we have to merge fisher diagonals
            for n, _ in self.model.named_parameters():
                self.fisher[n] = (self.fisher[n] + fisher_old[n] * t) / (
                            t + 1)  # Checked: it is better than the other option
                # self.fisher[n]=0.5*(self.fisher[n]+fisher_old[n])

        return

    def train_epoch(self, t, x, y):
        self.model.train()

        r = np.arange(x.size(0))
        np.random.shuffle(r)
        r = torch.LongTensor(r).cuda()

        # Loop batches
        for i in range(0, len(r), self.sbatch):
            if i + self.sbatch <= len(r):
                b = r[i:i + self.sbatch]
            else:
                b = r[i:]
            images = torch.autograd.Variable(x[b], volatile=False)
            targets = torch.autograd.Variable(y[b], volatile=False)

            # Forward current model
            outputs = self.model.forward(images)
            output = outputs[t]
            loss = self.criterion(t, output, targets)

            # Backward
            self.optimizer.zero_grad()
            loss.backward()
            torch.nn.utils.clip_grad_norm(self.model.parameters(), self.clipgrad)
            self.optimizer.step()

        return

    def eval(self, t, x, y):
        total_loss = 0
        total_acc = 0
        total_num = 0
        self.model.eval()

        r = np.arange(x.size(0))
        r = torch.LongTensor(r).cuda()

        # Loop batches
        for i in range(0, len(r), self.sbatch):
            if i + self.sbatch <= len(r):
                b = r[i:i + self.sbatch]
            else:
                b = r[i:]
            images = torch.autograd.Variable(x[b], volatile=True)
            targets = torch.autograd.Variable(y[b], volatile=True)

            # Forward
            outputs = self.model.forward(images)
            output = outputs[t]
            loss = self.criterion(t, output, targets)
            _, pred = output.max(1)
            hits = (pred == targets).float()

            # Log
            total_loss += loss.data.cpu().numpy() * len(b)
            total_acc += hits.sum().data.cpu().numpy()
            total_num += len(b)

        return total_loss / total_num, total_acc / total_num

    def criterion(self, t, output, targets):
        # Regularization for all previous tasks
        loss_reg = 0
        if t > 0:
            for (name, param), (_, param_old) in zip(self.model.named_parameters(), self.model_old.named_parameters()):
                loss_reg += torch.sum(self.fisher[name] * (param_old - param).pow(2)) / 2

        return self.ce(output, targets) + self.lamb * loss_reg

其中utils.py代码如下:

import os, sys
import numpy as np
from copy import deepcopy
import torch
from tqdm import tqdm


########################################################################################################################

def print_model_report(model):
    print('-' * 100)
    print(model)
    print('Dimensions =', end=' ')
    count = 0
    for p in model.parameters():
        print(p.size(), end=' ')
        count += np.prod(p.size())
    print()
    print('Num parameters = %s' % (human_format(count)))
    print('-' * 100)
    return count


def human_format(num):
    magnitude = 0
    while abs(num) >= 1000:
        magnitude += 1
        num /= 1000.0
    return '%.1f%s' % (num, ['', 'K', 'M', 'G', 'T', 'P'][magnitude])


def print_optimizer_config(optim):
    if optim is None:
        print(optim)
    else:
        print(optim, '=', end=' ')
        opt = optim.param_groups[0]
        for n in opt.keys():
            if not n.startswith('param'):
                print(n + ':', opt[n], end=', ')
        print()
    return


########################################################################################################################

def get_model(model):
    return deepcopy(model.state_dict())


def set_model_(model, state_dict):
    model.load_state_dict(deepcopy(state_dict))
    return


def freeze_model(model):
    for param in model.parameters():
        param.requires_grad = False
    return


########################################################################################################################

def compute_conv_output_size(Lin, kernel_size, stride=1, padding=0, dilation=1):
    return int(np.floor((Lin + 2 * padding - dilation * (kernel_size - 1) - 1) / float(stride) + 1))


########################################################################################################################

def compute_mean_std_dataset(dataset):
    # dataset already put ToTensor
    mean = 0
    std = 0
    loader = torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False)
    for image, _ in loader:
        mean += image.mean(3).mean(2)
    mean /= len(dataset)

    mean_expanded = mean.view(mean.size(0), mean.size(1), 1, 1).expand_as(image)
    for image, _ in loader:
        std += (image - mean_expanded).pow(2).sum(3).sum(2)

    std = (std / (len(dataset) * image.size(2) * image.size(3) - 1)).sqrt()

    return mean, std


########################################################################################################################

def fisher_matrix_diag(t, x, y, model, criterion, sbatch=20):
    # Init
    fisher = {}
    for n, p in model.named_parameters():
        fisher[n] = 0 * p.data
    # Compute
    model.train()
    for i in tqdm(range(0, x.size(0), sbatch), desc='Fisher diagonal', ncols=100, ascii=True):
        b = torch.LongTensor(np.arange(i, np.min([i + sbatch, x.size(0)]))).cuda()
        images = torch.autograd.Variable(x[b], volatile=False)
        target = torch.autograd.Variable(y[b], volatile=False)
        # Forward and backward
        model.zero_grad()
        outputs = model.forward(images)
        loss = criterion(t, outputs[t], target)
        loss.backward()
        # Get gradients
        for n, p in model.named_parameters():
            if p.grad is not None:
                fisher[n] += sbatch * p.grad.data.pow(2)
    # Mean
    for n, _ in model.named_parameters():
        fisher[n] = fisher[n] / x.size(0)
        fisher[n] = torch.autograd.Variable(fisher[n], requires_grad=False)
    return fisher


########################################################################################################################

def cross_entropy(outputs, targets, exp=1, size_average=True, eps=1e-5):
    out = torch.nn.functional.softmax(outputs)
    tar = torch.nn.functional.softmax(targets)
    if exp != 1:
        out = out.pow(exp)
        out = out / out.sum(1).view(-1, 1).expand_as(out)
        tar = tar.pow(exp)
        tar = tar / tar.sum(1).view(-1, 1).expand_as(tar)
    out = out + eps / out.size(1)
    out = out / out.sum(1).view(-1, 1).expand_as(out)
    ce = -(tar * out.log()).sum(1)
    if size_average:
        ce = ce.mean()
    return ce


########################################################################################################################

def set_req_grad(layer, req_grad):
    if hasattr(layer, 'weight'):
        layer.weight.requires_grad = req_grad
    if hasattr(layer, 'bias'):
        layer.bias.requires_grad = req_grad
    return


########################################################################################################################

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        pass

    try:
        import unicodedata
        unicodedata.numeric(s)
        return True
    except (TypeError, ValueError):
        pass

    return False
########################################################################################################################

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: PyTorch是一个开源的深度学习框架,它为持续学习提供了很好的支持。持续学习是指通过不断地学习新的数据、调整模型和继续训练,从而实现模型的优化和更新。下面是使用PyTorch实现持续学习的一些关键步骤: 1. 数据处理:将新的数据加载到PyTorch中,并进行预处理操作,例如数据标准化、数据增强等。可以使用PyTorch中的数据加载器(DataLoader)和数据预处理工具(transform)加快处理过程。 2. 模型加载:加载已经训练好的模型参数,可以使用PyTorch的torch.load()函数加载先前训练模型的参数。 3. 模型调整:根据新的数据特点,对模型进行微调或调整。可以使用PyTorch提供的灵活的模型定义和修改方式,例如修改模型的层结构、修改激活函数等。 4. 优化器选择:选择合适的优化器,例如Adam、SGD等,以在持续学习过程中调整模型的权重。 5. 训练过程:使用新的数据对模型进行训练,并反复迭代调整模型。可以使用PyTorch提供的自动微分功能,加快梯度计算和模型更新过程。 6. 模型保存:在每次训练迭代结束后,保存模型的最新参数。可以使用PyTorch的torch.save()函数保存模型参数。 7. 持续学习:重复上述步骤,对新的数据进行处理、模型调整和训练过程,以实现模型的持续学习。 通过上述步骤,使用PyTorch可以实现持续学习的过程。凭借其灵活性和强大的计算能力,PyTorch能够满足各种深度学习模型对于持续学习的需求,并为模型的优化提供支持。同时,PyTorch还提供了丰富的工具和函数,帮助开发者更高效地实现持续学习。 ### 回答2: PyTorch是一个开源的机器学习框架,它提供了丰富的工具和功能来支持持续学习持续学习指的是通过新数据的输入,持续改进和更新现有的模型,以适应不断变化的环境和任务。 PyTorch提供了一个灵活和可扩展的架构,使得持续学习变得更加容易。以下是在PyTorch中实现持续学习的一些关键步骤: 1. 数据管理:持续学习需要处理不断变化的数据。PyTorch中的DataLoader和Dataset类可以帮助加载和管理数据集。您可以创建一个数据加载器来批量加载新的数据集,并将其与之前的数据集合并。 2. 模型更新:当有新的数据到达时,您可以使用PyTorch的优化器来更新模型的参数,以适应新的数据。您可以使用反向传播算法计算损失,并调用优化器的`step`函数来更新模型的参数。 3. 继续训练:持续学习意味着在之前训练的基础上继续学习。您可以加载之前训练保存的模型,并在新的数据上进行训练。在PyTorch中,您可以使用`torch.load`函数加载之前训练的模型,并通过调用`train`函数来继续训练。 4. 模型评估:持续学习需要在新的数据上进行模型评估,以评估其性能和适应能力。您可以使用PyTorch中的评估函数和指标来评估模型的准确性和效果。 5. 灵活性:PyTorch的灵活性使得您可以自定义和调整模型结构,以适应不同的任务和数据。您可以根据新的数据特点调整模型的层次、结构和参数。 总之,PyTorch为持续学习提供了丰富的功能和易用的工具。通过管理数据、更新模型、继续训练和模型评估,您可以在PyTorch中有效地实现持续学习。 ### 回答3: 在PyTorch中实现持续学习的关键是使用动态图的特性和灵活的模型更新方法。 首先,PyTorch的动态图机制允许我们在运行时构建和修改模型图,这使得持续学习更加容易。我们可以将新的数据集添加到已经训练的模型上,并通过反向传播来更新模型的权重。这样,我们可以通过在已有模型上继续训练来逐步适应新的数据,而无需重新训练整个模型。 其次,持续学习的另一个重要问题是防止旧知识的遗忘。为了解决这个问题,我们可以使用增量学习方法,如Elastic Weight Consolidation(EWC)或Online Deep Learning(ODL)。这些方法通过使用正则化项或定义损失函数来限制新训练数据对旧知识的影响,从而保护旧有的模型参数。 此外,我们还可以使用PyTorch提供的模型保存和加载功能来实现持续学习。我们可以定期保存模型的参数和优化器状态,以便在需要时恢复模型,并继续训练过程。通过这种方式,我们可以持续积累更多的数据和知识,而无需从头开始每次都重新训练模型。 总的来说,PyTorch提供了灵活的动态图和丰富的工具,使得实现持续学习变得简单。我们可以通过动态修改模型图、使用增量学习方法来应对新数据和旧知识的挑战,并使用模型保存和加载功能来持续积累数据和知识。这些方法的组合可以帮助我们在PyTorch中实现高效的持续学习
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值