·迁移学习算法-DeepAdaptationNetworks
·迁移学习是一种学习的思想和模式。
·迁移学习作为机器学习的一个重要分支,侧重于将已经学习过的知识迁移应用于新的问题中。
·迁移学习的核心问题是,找到新问题和原问题之间的相似性,才可以顺利地实现知识的迁移。
·迁移学习,是指利用数据、任务、或模型之间的相似性,将在旧领域学习过的模型,应用于新领域的一种学习过程。
迁移学习例子
原因概括为以下四个方面:
1、大数据与少标注之间的矛盾
我们正处在一个大数据时代,每天每时,社交网络、智能交通、视频监控、行业物流等,都产生着海量的图像、文本、语音等各类数据。数据的增多,使得机器学习和深度学习模型可以依赖于如此海量的数据,持续不断地训练和更新相应的模型,使得模型的性能越来越好,越来越适合特定场景的应用。然而,这些大数据带来了严重的问题:总是缺乏完善的数据标注。
众所周知,机器学习模型的训练和更新,均依赖于数据的标注。然而,尽管我们可以获取到海量的数据,这些数据往往是很初级的原始形态,很少有数据被加以正确的人工标注。数据的标注是一个耗时且昂贵的操作,目前为止,尚未有行之有效的方式来解决这一问题。这给机器学习和深度学习的模型训练和更新带来了挑战。反过来说,特定的领域,因为没有足够的标定数据用来学习,使得这些领域一直不能很好的发展。
2、大数据与弱计算之间的矛盾
绝大多数普通用户是不可能具有这些强计算能力的。这就引发了大数据和弱计算之间的矛盾。在这种情况下,普通人想要利用这些海量的大数据去训练模型完成自己的任务,基本上不太可能。那么如何让普通人也能利用这些数据和模型?
3、普适化模型与个性化需求之间的矛盾
机器学习的目标是构建一个尽可能通用的模型,使得这个模型对于不同用户、不同设备、不同环境、不同需求,都可以很好地进行满足。这是我们的美好愿景。这就是要尽可能地提高机器学习模型的泛化能力,使之适应不同的数据情形。基于这样的愿望,我们构建了多种多样的普适化模型,来服务于现实应用。然而,这只能是我们竭尽全力想要做的,目前却始终无法彻底解决的问题。人们的个性化需求五花八门,短期内根本无法用一个通用的模型去满足。比如导航模型,可以定位及导航所有的路线。但是不同的人有不同的需求。比如有的人喜欢走高速,有的人喜欢走偏僻小路,这就是个性化需求。并且,不同的用户,通常都有不同的隐私需求。这也是构建应用需要着重考虑的。
所以目前的情况是,我们对于每一个通用的任务都构建了一个通用的模型。这个模型可以解决绝大多数的公共问题。但是具体到每个个体、每个需求,都存在其唯一性和特异性,一个普适化的通用模型根本无法满足。那么,能否将这个通用的模型加以改造和适配,使其更好地服务于人们的个性化需求?
4、特定应用的需求
机器学习已经被广泛应用于现实生活中。在这些应用中,也存在着一些特定的应用,它们面临着一些现实存在的问题。比如推荐系统的冷启动问题。一个新的推荐系统,没有足够的用户数据,如何进行精准的推荐一个崭新的图片标注系统,没有足够的标签,如何进行精准的服务?现实世界中的应用驱动着我们去开发更加便捷更加高效的机器学习方法来加以解决。
上述存在的几个重要问题,使得传统的机器学习方法疲于应对。迁移学习则可以很好地进行解决。
迁移学习是如何进行解决的呢
大数据与少标注:迁移数据标注
大数据与弱计算:模型迁移
普适化模型与个性化需求:自适应学习
特定应用的需求:相似领域知识迁移
为了满足特定领域应用的需求,我们可以利用上述介绍过的手段,从数据和模型方法上进行迁移学习。
总结
迁移学习VS传统机器学习
迁移学习的研究领域
依据目前较流行的机器学习分类方法,机器学习主要可以分为有监督、半监督和无监督机器学习三大类。同理,迁移学习也可以进行这样的分类。需要注意的是,依据的分类准则不同,分类结果也不同。在这一点上,并没有一个统一的说法。我们在这里仅根据目前较流行的方法,对迁移学习的研究领域进行一个大致的划分。
大体上讲,迁移学习的分类可以按照四个准则进行:按目标域有无标签分、按学习方法分、按特征分、按离线与在线形式分。不同的分类方式对应着不同的专业名词。当然,即使是一个分类下的研究领域,也可能同时处于另一个分类下。下面我们对这些分类方法及相应的领域作简单描述。
按目标域标签分
这种分类方式最为直观。类比机器学习,按照目标领域有无标签,迁移学习可以分为以下三个大类:
显然,少标签或无标签的问题(半监督和无监督迁移学习),是研究的热点和难点。
按学习方法分类
这是一个很直观的分类方式,按照数据、特征、模型的机器学习逻辑进行区分,再加上不属于这三者中的关系模式。
·基于实例的迁移,简单来说就是通过权重重用,对源域和目标域的样例进行迁移。就是说直接对不同的样本赋予不同权重,比如说相似的样本,我就给它高权重,这样我就完成了迁移,非常简单非常非常直接。
·基于模型的迁移,就是说构建参数共享的模型。这个主要就是在神经网络里面用的特别多,因为神经网络的结构可以直接进行迁移。比如说神经网络最经典的finetune就是模型参数迁移的很好的体现。
·基于关系的迁移,这个方法用的比较少,这个主要就是说挖掘和利用关系进行类比迁移。比如老师上课、学生听课就可以类比为公司开会的场景。这个就是一种关系的迁移。
按特征分类
按照特征的属性进行分类,也是一种常用的分类方法。这在最近的迁移学习综述[Weissetal.,2016]中给出。按照特征属性,迁移学习可以分为两个大类:
这也是一种很直观的方式:如果特征语义和维度都相同,那么就是同构;反之,如果特征完全不相同,那么就是异构。举个例子来说,不同图片的迁移,就可以认为是同构;而图片到文本的迁移,则是异构的。
按离线与在线形式分
按照离线学习与在线学习的方式,迁移学习还可以被分为:
目前,绝大多数的迁移学习方法,都采用了离线方式。即,源域和目标域均是给定的,迁移一次即可。这种方式的缺点是显而易见的:算法无法对新加入的数据进行学习,模型也无法得到更新。与之相对的,是在线的方式。即随着数据的动态加入,迁移学习算法也可以不断地更新。
迁移学习的应用
·迁移学习是机器学习领域的一个重要分支。因此,其应用并不局限于特定的领域。凡是满足迁移学习问题情景的应用,迁移学习都可以发挥作用。这些领域包括但不限于计算机视觉、文本分类、行为识别、自然语言处理、室内定位、视频监控、舆情分析、人机交互等。
计算机视觉
迁移学习已被广泛地应用于计算机视觉的研究中。特别地,在计算机视觉中,迁移学习方法被称为DomainAdaptation。Domainadaptation的应用场景有很多,比如图片分类、图片哈希等。
同一类图片,不同的拍摄角度、不同光照、不同背景,都会造成特征分布发生改变。因此,使用迁移学习构建跨领域的鲁棒分类器是十分重要的。
文本分类
医疗健康
医疗健康领域的研究正变得越来越重要。不同于其他领域,医疗领域研究的难点问题是,无法获取足够有效的医疗数据。在这一领域,迁移学习同样也变得越来越重要。
是进行一切研究的前提。在迁移学习中,有两个基本的概念:领域(Domain)和任务(Task)。它们是最基础的概念。
是进行学习的主体。领域主要由两部分构成:数据和生成这些数据的概率分布。通常我们用D来表示一个domain,用大写P来表示一个概率分布。
特别地,因为涉及到迁移,所以对应于两个基本的领域:源领域(SourceDomain)和目标领域(TargetDomain)。这两个概念很好理解。源领域就是有知识、有大量数据标注的领域,是我们要迁移的对象;目标领域就是我们最终要赋予知识、赋予标注的对象。知识从源领域传递到目标领域,就完成了迁移。
领域上的数据,我们通常用小写粗体x来表示,它也是向量的表示形式。例如,xi就表示第i个样本或特征。用大写的黑体X表示一个领域的数据,这是一种矩阵形式。我们用大写花体X来表示数据的特征空间。
通常我们用小写下标s和t来分别指代两个领域。结合领域的表示方式,则:Ds表示源领域,Dt表示目标领域。
值得注意的是,概率分布P通常只是一个逻辑上的概念,即我们认为不同领域有不同的概率分布,却一般不给出(也难以给出)P的具体形式。
任务(Task):是学习的目标。任务主要由两部分组成:标签和标签对应的函数。通常我们用花体Y来表示一个标签空间,用f(·)来表示一个学习函数。
相应地,源领域和目标领域的类别空间就可以分别表示为Ys和Yt。我们用小写ys和yt分别表示源领域和目标领域的实际类别。
常用符号总结
迁移学习的核心是,找到源领域和目标领域之间的相似性,并加以合理利用。这种相似性非常普遍。比如,不同人的身体构造是相似的;自行车和摩托车的骑行方式是相似的;国际象棋和中国象棋是相似的;羽毛球和网球的打球方式是相似的。这种相似性也可以理解为不变量。以不变应万变,才能立于不败之地。
找到相似性(不变量),是进行迁移学习的核心。
有了这种相似性后,下一步工作就是,如何度量和利用这种相似性。度量工作的目标有两点:一是很好地度量两个领域的相似性,不仅定性地告诉我们它们是否相似,更定量地给出相似程度。二是以度量为准则,通过我们所要采用的学习手段,增大两个领域之间的相似性,从而完成迁移学习。
定义在两个向量(两个点)上,这两个数据在同一个分布里。点x和点y的马氏距离为:
最大均值差异是迁移学习中使用频率最高的度量。Maximummeandiscrepancy,它度量在再生希尔伯特空间中两个分布的距离,是一种核学习方法。两个随机变量的MMD平方距离为
·基于样本的迁移
·基于模型的迁移
·基于特征的迁移
·基于关系的迁移
基于样本的迁移学习方法(InstancebasedTransferLearning)根据一定的权重生成规则,对数据样本进行重用,来进行迁移学习。图片形象地表示了基于样本迁移方法的思想。
源域中存在不同种类的动物,如狗、鸟、猫等,目标域只有狗这一种类别。在迁移时,为了最大限度地和目标域相似,我们可以人为地提高源域中属于狗这个类别的样本权重。
虽然实例权重法具有较好的理论支撑、容易推导泛化误差上界,但这类方法通常只在领域间分布差异较小时有效,因此对自然语言处理、计算机视觉等任务效果并不理想。
基于特征的迁移方法(FeaturebasedTransferLearning)是指将通过特征变换的方式互相迁移[Liuetal.,2011,Zhengetal.,2008,HuandYang,2011],来减少源域和目标域之间的差距;或者将源域和目标域的数据特征变换到统一特征空间中[Panetal.,2011,Longetal.,2014b,Duanetal.,2012],然后利用传统的机器学习方法进行分类识别。根据特征的同构和异构性,又可以分为同构和异构迁移学习。图片很形象地表示了两种基于特征的迁移学习方法。
基于模型的迁移方法(Parameter/ModelbasedTransferLearning)是指从源域和目标域中找到他们之间共享的参数信息,以实现迁移的方法。这种迁移方式要求的假设条件是:源域中的数据与目标域中的数据可以共享一些模型的参数。
基于关系的迁移学习方法示意图
数据分布自适应(DistributionAdaptation)是一类最常用的迁移学习方法。这种方法的基本思想是,由于源域和目标域的数据概率分布不同,那么最直接的方式就是通过一些变换,将不同的数据分布的距离拉近。
根据数据分布的性质,这类方法又可以分为边缘分布自适应、条件分布自适应、以及联合分布自适应。
图片形象地表示了几种数据分布的情况。简单来说,数据的边缘分布不同,就是数据整体不相似。数据的条件分布不同,就是数据整体相似,但是具体到每个类里,都不太相似。
迁移成分分析(TransferComponentAnalysis)是一种边缘分布自适应方法(MarginalDistributionAdaptation)
其目标是减小源域和目标域的边缘概率分布的距离,从而完成迁移学习
从形式上来说,边缘分布自适应方法是用P(xs)和P(xt)之间的距离来近似两个领域之间的差异。即:
边缘分布自适应的方法最早由香港科技大学杨强教授团队提出[Panetal.,2011]
问题:但是世界上有无穷个这样的,我们肯定不能通过穷举的方法来找的。那么怎么办呢?
迁移学习的本质:最小化源域和目标域的距离。
能否先假设这个是已知的,然后去求距离,看看能推出什么?
以上式子下面的条件是什么意思呢?那个min的目标就是要最小化源域和目标域的距离,加上W的约束让它不能太复杂。下面的条件是是要实现第二个目标:维持各自的数据特征。
TCA要维持的特征是scattermatrix,就是数据的散度。就是说,一个矩阵散度怎么计算?对于一个矩阵A,它的scattermatrix就是AHA。这个H就是上面的中心矩阵。
TCA和PCA的效果对比
可以很明显地看出,对于概率分布不同的两部分数据,在经过TCA处理后,概率分布更加接近。这说明了TCA在拉近数据分布距离上的优势。
迁移学习算法-DeepAdaptationNetworks
from__future__importprint_function
importargparse
importtorch
importtorch.nn.functionalasF
importtorch.optimasoptim
fromtorch.autogradimportVariable
importos
importmath
importdata_loader
importResNetasmodels
fromtorch.utilsimportmodel_zoo
os.environ['CUDA_VISIBLE_DEVICES']='1'
#Trainingsettings
batch_size=32
epochs=200
lr=0.01
momentum=0.9
no_cuda=False
seed=8
log_interval=10
l2_decay=5e-4
root_path='./dataset/'
source_name='amazon'
target_name='webcam'
cuda=notno_cudaandtorch.cuda.is_available()
torch.manual_seed(seed)
ifcuda:
torch.cuda.manual_seed(seed)
kwargs={'num_workers':1,'pin_memory':True}ifcudaelse{}
source_loader=data_loader.load_training(root_path,source_name,batch_size,kwargs)
target_train_loader=data_loader.load_training(root_path,target_name,batch_size,kwargs)
target_test_loader=data_loader.load_testing(root_path,target_name,batch_size,kwargs)
len_source_dataset=len(source_loader.dataset)
len_target_dataset=len(target_test_loader.dataset)
len_source_loader=len(source_loader)
len_target_loader=len(target_train_loader)
defload_pretrain(model):
pretrained_dict=model_zoo.load_url(url)
model_dict=model.state_dict()
fork,vinmodel_dict.items():
ifnot'cls_fc'ink:
model_dict[k]=pretrained_dict[k[k.find('.')+1:]]
model.load_state_dict(model_dict)
returnmodel
deftrain(epoch,model):
LEARNING_RATE=lr/math.pow((1+10*(epoch-1)/epochs),0.75)
print('learningrate{:.4f}'.format(LEARNING_RATE))
optimizer=torch.optim.SGD([
{'params':model.sharedNet.parameters()},
{'params':model.cls_fc.parameters(),'lr':LEARNING_RATE},
],lr=LEARNING_RATE/10,momentum=momentum,weight_decay=l2_decay)
model.train()
iter_source=iter(source_loader)
iter_target=iter(target_train_loader)
num_iter=len_source_loader
foriinrange(1,num_iter):
data_source,label_source=iter_source.next()
data_target,_=iter_target.next()
ifi%len_target_loader==0:
data_source,label_source=data_source.cuda(),label_source.cuda()
data_target=data_target.cuda()
data_source,label_source=Variable(data_source),Variable(label_source)
data_target=Variable(data_target)
optimizer.zero_grad()
label_source_pred,loss_mmd=model(data_source,data_target)
loss_cls=F.nll_loss(F.log_softmax(label_source_pred,dim=1),label_source)
gamma=2/(1+math.exp(-10*(epoch)/epochs))-1
loss=loss_cls+gamma*loss_mmd
loss.backward()
optimizer.step()
ifi%log_interval==0:
print('TrainEpoch:{}[{}/{}({:.0f}%)]\tLoss:{:.6f}\tsoft_Loss:{:.6f}\tmmd_Loss:{:.6f}'.format(
epoch,i*len(data_source),len_source_dataset,
100.*i/len_source_loader,loss.data[0],loss_cls.data[0],loss_mmd.data[0]))
deftest(model):
model.eval()
test_loss=0
correct=0
fordata,targetintarget_test_loader:
data,target=data.cuda(),target.cuda()
data,target=Variable(data,volatile=True),Variable(target)
s_output,t_output=model(data,data)
test_loss+=F.nll_loss(F.log_softmax(s_output,dim=1),target,size_average=False).data[0]#sumupbatchloss
pred=s_output.data.max(1)[1]#gettheindexofthemaxlog-probability
correct+=pred.eq(target.data.view_as(pred)).cpu().sum()
test_loss/=len_target_dataset
print('\n{}set:Averageloss:{:.4f},Accuracy:{}/{}({:.2f}%)\n'.format(
target_name,test_loss,correct,len_target_dataset,
100.*correct/len_target_dataset))
returncorrect
if__name__=='__main__':
model=models.DANNet(num_classes=31)
print(model)
model.cuda()
model=load_pretrain(model)
forepochinrange(1,epochs+1):
train(epoch,model)
t_correct=test(model)
ift_correct>correct:
correct=t_correct
print('source:{}totarget:{}maxcorrect:{}maxaccuracy{:.2f}%\n'.format(
source_name,target_name,correct,100.*correct/len_target_dataset))