文章K-means算法介绍
K-means算法介绍 K-means算法是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。 算法过程如下: 1)从N个文档随机选取K个文档作为中心点; 2)对剩余的每个文档测量其到每个中心点的距离,并把它归到最近的质心的类; 3)重新计算已经得到的各个类的中心点; 4)迭代2~3步直至新的质心与原质心相等或小于指定阈值,算法结束。 算法优缺点: 优点: 原理简单速度快对大数据集有比较好的伸缩性缺点: 需要指定聚类 数量K对异常值敏感对初始值敏感代码实现:首先我们随机生成200个点,就取(0,2000)之间的,并确定质心个数,这里就取个3个质心,也是随机生成(可以根据需求改变)如下: import randomimport matplotlib.pyplot as plt randomx = [random.randint(0,2000) for in range(200)]randomy = [random.randint(0,2000) for in range(200)]random_poinsts = [(x, y) for x, y in zip(random_x, random_y)] def generaterandom_point(min,max): return random.randint(min,max),random.randint(min,max_)k1,k2,k3 = generate_random_point(-100,100),generate_random_point(-100,100),generate_random_point(-100,100) plt.scatter(k1[0],k1[1],color = ‘red’,s=100)plt.scatter(k2[0],k2[1],color = ‘blue’,s=100)plt.scatter(k3[0],k3[1],color = ‘green’,s=100)plt.scatter(random_x,random_y) 结果如下: 接着导入numpy,来计算各个点与质心的距离,并根据每个点与质心的距离分类,与第一个点近则分配在列表的第一个位置,离第二个近则分配到第二个位置,以此类推,如下 import numpy as npdef dis(p1,p2): #这里的p1,p2是一个列表[number1,number2] 距离计算 return np.sqrt((p1[0] - p2[0])2 + (p1[1]-p2[1])2)random_poinsts = [(x, y) for x, y in zip(random_x, random_y)] #将100个随机点塞进列表groups = [[],[],[]] #100个点分成三类for p in random_poinsts: #k1,k2,k3是随机生成的三个点 distances = [dis(p,k) for k in [k1,k2,k3]] min_index = np.argmin(distances)#取距离最近质心的下标 groups[min_index].append(p)groups 结果如下:[[(1000, 867), (1308, 840), (1999, 1598), (1606, 1289), (1324, 1044), (780, 923), (1915, 788), (443, 980), (687, 908), (1763, 1039), (1687, 1372), (1932, 1759), (1274, 739), (939, 1302), (790, 1169), (1776, 1572), (1637, 1042),….可以看到,这200个点根据与三个质心的距离远近不同,已经被分成了三类,此时groups里面有三个列表,这三个列表里分别是分配给三个质心的点的位置,接着我们将其可视化,并且加入循环来迭代以此找到相对最优的质点,代码如下: previous_kernels = [k1,k2,k3]circle_number = 10for n in range(circle_number): plt.close() #将之前的生成的图片关闭 kernel_colors = [‘red’,’yellow’,’green’] new_kernels =[] plt.scatter(previous_kernels[0][0],previous_kernels[0][1],color = kernel_colors[0],s=200) plt.scatter(previous_kernels[1][0],previous_kernels[1][1],color = kernel_colors[1],s=200) plt.scatter(previous_kernels[2][0],previous_kernels[2][1],color = kernel_colors[2],s=200) groups = [[],[],[]] #100个点分成三类 for p in random_poinsts: #k1,k2,k3是随机生成的三个点 distances = [dis(p,k) for k in previous_kernels] min_index = np.argmin(distances)#取距离最近质心的下标 groups[min_index].append(p) print('第{}次'.format(n+1)) for i,g in enumerate(groups): g_x = [_x for _x,_y in g] g_y = [_y for _x,_y in g] n_k_x,n_k_y = np.mean(g_x),np.mean(g_y) new_kernels.append([n_k_x,n_k_y]) print('三个点之前的质心和现在的质心距离:{}'.format(dis(previous_kernels[i],[n_k_x,n_k_y]))) plt.scatter(g_x,g_y,color = kernel_colors[i]) plt.scatter(n_k_x,n_k_y,color = kernel_colors[i],alpha= 0.5,s=200) previous_kernels = new_kernels 结果如下:第1次三个点之前的质心和现在的质心距离:344.046783724601三个点之前的质心和现在的质心距离:178.67567512699137三个点之前的质心和现在的质心距离:85.51258602308063第2次三个点之前的质心和现在的质心距离:223.75162213961798三个点之前的质心和现在的质心距离:41.23571511332308三个点之前的质心和现在的质心距离:132.0752155320645第3次三个点之前的质心和现在的质心距离:87.82012730359548三个点之前的质心和现在的质心距离:22.289121504444285三个点之前的质心和现在的质心距离:33.55374236991017第4次三个点之前的质心和现在的质心距离:50.94506045880864三个点之前的质心和现在的质心距离:25.754704854433683三个点之前的质心和现在的质心距离:23.145028187286528第5次三个点之前的质心和现在的质心距离:66.35519842692533三个点之前的质心和现在的质心距离:31.90944410706013三个点之前的质心和现在的质心距离:36.247409926389686第6次三个点之前的质心和现在的质心距离:46.17069651194525三个点之前的质心和现在的质心距离:15.076857795406966三个点之前的质心和现在的质心距离:42.59620276776667第7次三个点之前的质心和现在的质心距离:36.7751709217284三个点之前的质心和现在的质心距离:15.873333735074496三个点之前的质心和现在的质心距离:23.469882661161705第8次三个点之前的质心和现在的质心距离:0.0三个点之前的质心和现在的质心距离:0.0三个点之前的质心和现在的质心距离:0.0第9次三个点之前的质心和现在的质心距离:0.0三个点之前的质心和现在的质心距离:0.0三个点之前的质心和现在的质心距离:0.0第10次三个点之前的质心和现在的质心距离:0.0三个点之前的质心和现在的质心距离:0.0三个点之前的质心和现在的质心距离:0.0

3

SAN

lgx·2022-05-06 20:05 0 阅读 203
文章关系抽取任务的模型与实现细节
由于需要构建知识图谱,所以在实体识别的基础上,我们需要构建一个模型来识别同一个句子中实体间的关系。关系抽取本身是一个分类问题。给定两个实体和两个实体共同出现的句子文本,判别两个实体之间的关系。 在具体实现的过程中,主要参考了 crownpku_github 的模型结构。他的实践中使用了双向 GRU,字与句子的双重Attention模型,以天然适配中文特性的字向量(charactor embedding)作为输入。以下主要介绍了本次实践的一些细节,具体模型及代码请参考 github 下面主要从如下几个方面进行叙述: 为什么要选择这个模型?特征工程是如何做到?有哪些参数,参数量有多大现在使用的方法有什么缺点,如何进行改进? 模型构建BiGRU加字级别Attention的模型想法来自文章 Attention-Based Bidirectional Long Short-Term Memory Networks for Relation Classification。在这篇文章中使用的模型是BiLSTM+Attention。相比于单向一层的RNN,使用BiLSTM能够更好捕捉双向的语义关系,并且能够在一定程度上减小梯度消失带来的问题。而注意力机制可以聚焦到影响分类结果的核心词语,在不使用额外知识的条件下捕捉到句子间重要的语义信息。这里将原文的模型结构中的LSTM改为GRU,且对句子中的每一个中文字符输入为character embedding。这样的模型对每一个句子输入做训练,并加入字级别的attention。 句子级别Attention的想法来自文章 Neural Relation Extraction with Selective Attention over Instances 。针对远程监督场景下的关系抽取中存在的,由于误标签传播引起的训练数据噪声过大的问题,论文作者在关系语句层面上引入Attention机制,通过赋予包含某三元组的句子的不同的权重,从而减少噪声,进而提升学习效果。这里将其中对每个句子进行encoding的CNN模块换成上面的双向GRU模型。这样的模型对每一种类别的句子输入做共同训练,加入句子级别的attention。 假设 一个训练样本中,即一个句子中只包含两个实体,且这两个实体之间一定是有关系的;两个实体之间只存在一种关系,也就是说一个句子中只隐式的包含一种关系 特征构建:输入数据由字向量与位置向量组成。对于每个字,首先确定这个字在词表中的id(用于在训练时获取其id对应的词向量),然后获得这个词与句子中两个实体的距离,这个距离的最大范围规定在-60到60之间,小于的部分设置为0,大于的部分设置为123。 在模型构建中,使用已经训练好的字向量作为字的初始化向量(向量维度为100),使用随机初始化的方式初始化位置向量(向量为5),在模型训练的过程中对位置向量的参数矩阵继续训练。对于模型输入来说,其向量维度为110,即同一字向量与两个位置向量拼接而成。最大文本长度设置为70。 模型细节: BiLSTM + 字级别Attention(向量计算过程基本按采用原论文中的方法) 准备正序和逆序的文本序列及位置序列,通过向量矩阵分别获取文本向量和位置向量,然后将二者进行拼接;拼接完毕后将正序和逆序的向量分别通过BiLSTM层和dropout层,得到向量结果按位相加; BiLSTM输出的结果首先通过一个tanh激活函数,$M = tanh(H)$;然后与一个维度为文本序列长度的参数矩阵相乘,并通过softmax得到权值(即Attention的结果)$\alpha = softmax(\omega^T M)$;将这个权值加到BiLSTM的输出结果上,得到句子最终的向量表示,$r = H \alpha^T$。公式表示为: 句子级别 Attention 从一个batch中每次取出一个向量,首先计算它的tanh函数结果,然后计算当前这个句子的权值,这个权值的计算过程使用了$softmax$ ($\alpha_i = \frac {exp(e_i)}{\sum_k exp(e_k)}$),输入的数据 $e_i$ 为当前句子与对应关系的打分结果,这个结果为 $e_i = x_iAr$,其中 $x_i$ 为句向量,$A$ 为权重的对角矩阵,$r$ 为具体关系r的向量表示,这两个都是可训练的参数。得到的Attention参数 $\alpha_i$ 要乘以对应句子向量得到整个集合上的结果,公式表示为 $s = \sum_i \alpha_ix_i$ 模型最终的输出结果为 $o = Ms+d$ ,其中 $M$ 为关系矩阵的表示,$d$ 为一个偏置向量,这两个都是可训练的参数。这里相当于将整个集合的 $s$ 作为输入,为其配置参数和偏置,$o$ 为这一层的输出,后面接softmax输出每个类别下的概率。 模型参数说明: BiLSTM模型中的参数,2倍的LSTM中的参数字级别attention中的参数有1个,大小为神经元个数*1句级别attention中的参数有4个,分别是上文的A,r,M,d,参数量见re_model.py文件 训练情况:当前关系类别只有3个,分别是:【正向关系,反向关系,没有关系】,训练数据3000条,测试数据1000条; 其中没有关系的训练数据个数为300,通过处理数据进行构造的。 评价方法: correct_by_relation表示:预测结果显示有关系,实际标签也是有关系,并且两个的结果是吻合的,进行计数(TP);guessed_by_relation表示:预测显示有关系则全部进行计数(TP+FP);gold_by_relation:实际标签显示有关系则全部进行计数(TP+FN)。 def score(key, prediction, verbose=False): correct_by_relation = Counter() guessed_by_relation = Counter() gold_by_relation = Counter() # Loop over the data to compute a score for row in range(len(key)): gold = key[row] # 存放真实关系 guess = prediction[row] # 存放预测关系 if gold == NO_RELATION and guess == NO_RELATION: pass elif gold == NO_RELATION and guess != NO_RELATION: guessed_by_relation[guess] += 1 elif gold != NO_RELATION and guess == NO_RELATION: gold_by_relation[gold] += 1 elif gold != NO_RELATION and guess != NO_RELATION: guessed_by_relation[guess] += 1 gold_by_relation[gold] += 1 if gold == guess: correct_by_relation[guess] += 1 # 计算presicion和recall,f1的值 prec_micro = 1.0 if sum(guessed_by_relation.values()) > 0: prec_micro = float(sum(correct_by_relation.values())) / float(sum(guessed_by_relation.values())) recall_micro = 0.0 if sum(gold_by_relation.values()) > 0: recall_micro = float(sum(correct_by_relation.values())) / float(sum(gold_by_relation.values())) f1_micro = 0.0 if prec_micro + recall_micro > 0.0: f1_micro = 2.0 * prec_micro * recall_micro / (prec_micro + recall_micro) 优化方法: 当前的位置向量计算方式是,句子中的每一个字分别到两个实体间的距离。但这个距离是每个字到实体第一个字的距离,可以尝试为每个字到实体最后一个字的距离也做位置向量,进行向量的拼接或是按位相加; batch_size的值会影响预测的准确率,因为attention的计算指定了batch_size=50,所以在预测阶段,如果batch_size的维持在50左右(甚至大于50),则预测准确率也会维持在80%以上;而如果batch_size比较小,准确率也会伴随有一定程度的降低; 比较理想的数据是,每一个完成句子中应该只包含了一种实体关系。但如果这个句子包含多个实体,且这多个实体之间又存在多个关系,这就很难对预测结果进行评价了。因为预测结果只能有1个。例如一个句子中存在3个实体1,2,3,两个关系A(1,2),B(1,3),预测结果为A,但是实际标注为【1,3,B,句子】,但是如果不看实体本身的话,B关系确实也是这个句子中的一种关系。结论:单纯针对一个句子进行预测,可能会遗漏掉很多重要信息(可以参考细粒度情感分析的相关项目;或者使用多分类的方法,一个句子中包含多种关系);会存在一些数据不平衡的情况,主要优化方式采用了欠采样的策略进行优化的,准确率提升并不明显。由于采用随机抽样的方式进行构建数据集,欠采样有可能漏掉一些包含关键信息的句子样本。解决数据不平衡的问题,还需要进一步实践。 模型总结:(1)关系抽取本身与分类模型并没有什么区别。首先我们需要知道每一条文本数据中包含了哪两个实体,并且他们之间存在哪种关系,这里的关系就是标签; (2)输入数据,是采用字向量(对句子中的每个字做embedding)和位置向量(对句子中每个字与两个实体之间的距离进行编码)拼接的方式,共同组成模型的输入; (3)在最终输出层加入了attention层,对每个句子中每个字做attention,得到的结果再接全连接层和softmax,得到的结果就是softmax后的logits结果,对这个结果进行评价 (4)可优化的方面见3.

0

自然语言处理

Botanic·2022-05-06 20:05 0 阅读 190
文章计算机视觉之图像分类
蘑菇分类赛题背景: 本次赛题背景是日常生活中蘑菇类别较多,而其中包含了很多有毒蘑菇,人很难辨别,容易引起误食,该比赛想通过深度学习的方法帮助人们识别出毒蘑菇。本次竞赛使用的数据集由北欧真菌学家协会提供的9 种常见北欧蘑菇属的图像组成。 赛题分析: 这个题目就是一个图像分类问题,给定了6045张图片作为训练集,675张图片作为测试集,对于线下的10%数据。 实验过程: 1、5折交叉划分训练集和验证集,遍历每一个类别,训练与验证数据比例大致相同 2、试验了各种分类模型 3、预测的时候使用水平翻转求平均的简单策略 4、测试各种超参数 batchsize,学习率,增强策略,优化器,损失函数等 提分的一些操作: 1、标签平滑 2、模型选择 Swim-Transformer 3、数据集划分 9:1验证集有过拟合问题,8:2稍微好一些 4、模型融合 5、随机裁剪、随机擦除 6、tta 最终模型和参数: (1)数据集划分: 训练集5折交叉 训练集:验证集=8:2 (2)模型选择: Swim-Transformer 预训练模型: swin_large_patch4_window12_384_22k.pth (3)inputsize: 383*384 (4)batchsize: 4 (5)max_epochs: 30 (6)学习率: 阶梯下降学习率 def lr_scheduler(optimizer, epoch): if epoch < 10: lr = 1e-3 elif epoch < 20: lr = 1e-4 else: lr = 1e-5 for param_group in optimizer.param_groups: param_group['lr'] = lr return optimizer ( 7)优化器: self.optimizer = optim.SGD((self.model_ft.parameters()), lr=1e-3, momentum=momentum, weight_decay=0.0005) (8)损失函数: LabelSmoothingCrossEntropy(smoothing=0.1).cuda() (9)增强策略: 训练集: 随机裁剪、水平翻转、随机擦除 验证集:简单缩放 data_transforms = { 'train': transforms.Compose([ transforms.RandomResizedCrop((input_size, input_size)), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.RandomErasing(p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3), value=0, inplace=False), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize((input_size,input_size)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), (10)测试增强: 正常图片+ 水平翻转 -> 求平均 (11)融合策略: 保存每折训练过程中最大Acc和最小Loss的模型,数据集5折交叉,共5*2=10个模型进行融合 教训总结: 1、过早的模型融合,忽略了单个模型的性能比较 2、验证集过拟合问题 3、代码没有线下测试,导致线上出问题,浪费了很多实验时间

0

CNN

flyai会员1644651721·2022-05-06 20:05 0 阅读 218
文章MnasNet复现以及一些感想
概述MnasNet( mobile neural architecture search),是谷歌提出的一个轻量化网络。 卷积神经网络一直对于移动设备是个挑战,移动端模型一般要求模型小而快,同时对精度也有要求。尽管CNN模型在移动端做了各种改进提升,但是当考虑到许多架构的可能性时,很难手动平衡这些权衡。自动移动神经架构搜索 (MNAS)方法,它明确地将模型延迟纳入主要目标,以便搜索能够识别一个在准确性和延迟之间实现良好权衡的模型。 与之前的方法预估延迟不同的是,他们直接采用真实环境中手机上的模型预测延时,之前方法通常是采用不精确的模式(如:FLOPS)。为了进一步在灵活性和搜索空间大小之间取得适当的平衡,作者提出了一种新的分解层次搜索空间,它鼓励整个网络中的层多样性。实验结果表明,他们的方法始终优于当时最先进的移动端的CNN跨多个视觉任务的模型。在ImageNet分类任务中取得精确度为75.2%的top1,在手机端的延时为78ms,速度是mobileNetV2的1.8倍,同时精确度比其高0.5%。 Mnasnet网络是介于mobilenetV2和mobilenetV3之间的一个网络,这个网络是采用强化学习搜索出来的一个网络,具体模式如下: 实验方法:像在ImageNet或COCO这样的大型任务上直接搜索CNN模型是昂贵的,因为每个模型需要几天才能收敛。虽然以前的方法主要对较小的任务(如CIFAR-10)执行模型搜索。在本文中,作者直接在ImageNet训练集上执行模型搜索,但训练步骤较少(5epoch)。通常,从训练集中随机选择50K图像作为固定验证集。为了确保精度的提高来自于搜索空间,使用了与NASNet相同的RNN控制器,尽管它效率不高: 在64台TPUv2设备上,每个模型搜索需要4.5天。在训练过程中,通过在Pixel 1手机的单线程大CPU内核上运行来测量每个采样模型的真实延迟。总的来说,大约采样了8K个模型,但是只有15个性能最好的型号被传输到完整的ImageNet,只有1个模型可以迁移到到COCO数据集上使用。 模型结构 与之前的其他模型不同的是,此模型使用了3X3和5X5的卷积,这和之前其他网络不同点。左图为模型的主结构,右图为模型的子模块具体指代。 实现mnasnet的实现基于pytorch的实现 由于paddlepaddle和pytorch的接口实现基本用法差别不大,所以在复现中实现的速度要快很多,但是同时也引入了新的问题,我们会一一说明。 pytorch的实现在关键点上的超参数以及具体实现基本已经给出。我们做的主要是实现Paddle版本的模型。 代码的具体实现在路径:work/PP-Mnasnet/net/models/mnasnet.py下面,大家有问题的可以细看。代码结构如下 参数及方法设置论文中关于优化器以及超参数学习率等参数,论文中都已经给出,但是实际的由于训练使用的硬件差异,我们不可能按照论文中的参数直接拿来使用。 先列举论文中用到的一些方法及参数: input_size: 224 X 224bach_size: 4Kwarm_up: True / 5 epochlr_scheduler: RMSProplr:0.256dropout:0.2momentum:0.9单看batch_size的大小4K,这就不是一般硬件能够达到的要求(据说这个模型在搜索出来的时候,资金花费是100K$),所以Batch_size根据实际情况来进行设定; 相对应的lr我们也应该进行调整,不宜设置为论文中的那样,基础的从0.001开始就行。如果最初的lr设置过大,基本在进行几十个epoch后,acc和其他参数指标基本没有大的变化,类似如下: top1: 0.00090, top5: 0.00473, lr: 0.20480, loss: 7.93936, avg_reader_cost: 0.04303 sec, avg_batch_cost: 0.10214 sec, avg_samples: 64.0, avg_ips: 626.62028top1: 0.00105, top5: 0.00488, lr: 0.20480, loss: 7.69394, avg_reader_cost: 0.04656 sec, avg_batch_cost: 0.10620 sec, avg_samples: 64.0, avg_ips: 602.63657top1: 0.00094, top5: 0.00434, lr: 0.20480, loss: 8.00038, avg_reader_cost: 0.04546 sec, avg_batch_cost: 0.10643 sec, avg_samples: 64.0, avg_ips: 601.34891top1: 0.00086, top5: 0.00512, lr: 0.20480, loss: 7.47677, avg_reader_cost: 0.04140 sec, avg_batch_cost: 0.10397 sec, avg_samples: 64.0, avg_ips: 615.57468top1: 0.00125, top5: 0.00508, lr: 0.20480, loss: 7.45593, avg_reader_cost: 0.04609 sec, avg_batch_cost: 0.10522 sec, avg_samples: 64.0, avg_ips: 608.27140top1: 0.00086, top5: 0.00527, lr: 0.20480, loss: 7.76873, avg_reader_cost: 0.04692 sec, avg_batch_cost: 0.10712 sec, avg_samples: 64.0, avg_ips: 597.46578top1: 0.00078, top5: 0.00453, lr: 0.20480, loss: 7.49132, avg_reader_cost: 0.04431 sec, avg_batch_cost: 0.10443 sec, avg_samples: 64.0, avg_ips: 612.87012top1: 0.00074, top5: 0.00492, lr: 0.20480, loss: 7.57973, avg_reader_cost: 0.05430 sec, avg_batch_cost: 0.11359 sec, avg_samples: 64.0, avg_ips: 563.42090top1: 0.00086, top5: 0.00508, lr: 0.20480, loss: 7.92624, avg_reader_cost: 0.04599 sec, avg_batch_cost: 0.10737 sec, avg_samples: 64.0, avg_ips: 596.08218top1: 0.00102, top5: 0.00465, lr: 0.20480, loss: 8.07673, avg_reader_cost: 0.05052 sec, avg_batch_cost: 0.10950 sec, avg_samples: 64.0, avg_ips: 584.49763warmup是较好的提分策略,并且能够在实际过程中加快模型拟合。由于训练的数据集使用的是ImageNet,分类为1000,完整的数据集大概144G,如果用aistudio我们也需要训练很久。 在确定了上述的方法策略后,最初的训练集在官方提供的数据集大概66G上直接进行训练。但是实际的训练在经过一天后,实际的acc增长还是比较低。当时采用了新的策略:在miniImageNet上进行训练,大概12个小时候就拟合了。我们将此模型在官方提供的数据集上进行训练,开始的acc可以达到0.22左右。这要比实际的直接进行训练速度要快很多。 训练代码的实现在:work/PP-Mnasnet/net/train.py这个目录下。这样在训练了大概三天后,我们的模型acc精度可以达到0.65左右: [2021/12/30 13:07:21] root INFO: [Epoch 91, iter: 16400] top1: 0.63598, top5: 0.83176, lr: 0.00120, loss: 1.79083, avg_reader_cost: 0.05147 sec, avg_batch_cost: 0.10281 sec, avg_samples: 64.0, avg_ips: 622.48323 images/sec.[2021/12/30 13:08:16] root INFO: [Epoch 91, iter: 16800] top1: 0.63836, top5: 0.83211, lr: 0.00120, loss: 1.45224, avg_reader_cost: 0.04990 sec, avg_batch_cost: 0.10145 sec, avg_samples: 64.0, avg_ips: 630.85575 images/sec.[2021/12/30 13:09:10] root INFO: [Epoch 91, iter: 17200] top1: 0.63187, top5: 0.83004, lr: 0.00120, loss: 1.95962, avg_reader_cost: 0.04719 sec, avg_batch_cost: 0.09977 sec, avg_samples: 64.0, avg_ips: 641.49160 images/sec.[2021/12/30 13:10:05] root INFO: [Epoch 91, iter: 17600] top1: 0.63000, top5: 0.83313, lr: 0.00120, loss: 1.98715, avg_reader_cost: 0.05027 sec, avg_batch_cost: 0.10245 sec, avg_samples: 64.0, avg_ips: 624.67859 images/sec.[2021/12/30 13:10:59] root INFO: [Epoch 91, iter: 18000] top1: 0.62883, top5: 0.82902, lr: 0.00120, loss: 1.93626, avg_reader_cost: 0.04727 sec, avg_batch_cost: 0.10032 sec, avg_samples: 64.0, avg_ips: 637.96714 images/sec.[2021/12/30 13:11:53] root INFO: [Epoch 91, iter: 18400] top1: 0.62855, top5: 0.82527, lr: 0.00120, loss: 1.35887, avg_reader_cost: 0.04998 sec, avg_batch_cost: 0.10153 sec, avg_samples: 64.0, avg_ips: 630.35848 images/sec.[2021/12/30 13:12:49] root INFO: [Epoch 91, iter: 18800] top1: 0.62773, top5: 0.82719, lr: 0.00120, loss: 1.83990, avg_reader_cost: 0.05086 sec, avg_batch_cost: 0.10312 sec, avg_samples: 64.0, avg_ips: 620.65365 images/sec.[2021/12/30 13:13:43] root INFO: [Epoch 91, iter: 19200] top1: 0.63160, top5: 0.82840, lr: 0.00120, loss: 1.59238, avg_reader_cost: 0.04715 sec, avg_batch_cost: 0.10000 sec, avg_samples: 64.0, avg_ips: 639.99664 images/sec.[2021/12/30 13:14:38] root INFO: [Epoch 91, iter: 19600] top1: 0.63152, top5: 0.83004, lr: 0.00120, loss: 1.68316, avg_reader_cost: 0.05057 sec, avg_batch_cost: 0.10349 sec, avg_samples: 64.0, avg_ips: 618.40716 images/sec.[2021/12/30 13:15:31] root INFO: [Epoch 91, iter: 20000] top1: 0.63129, top5: 0.82945, lr: 0.00120, loss: 1.62996, avg_reader_cost: 0.04641 sec, avg_batch_cost: 0.09755 sec, avg_samples: 64.0, avg_ips: 656.05389 images/sec.[2021/12/30 13:15:34] root INFO: The best model is in epoch [91] and the acc1 is [0.6335090398788452]论文复现流程:官方在论文复现方面有个很好的流程,具体可参考 在复现中如果出现精度等其他问题,可以参考官方推荐的流程进行核对对齐 出现的问题(目前已初步知晓):在acc达到0.65后就没有继续提升,论文中以及Pythorch实现的acc top1可以达到0.735。 在复现中断了一段时间后,关注到有人在组网的网络可分离卷积网络最后中加入relu(在模型实现代码中work/PP-Mnasnet/net/models/mnasnet.py的第129行添加这个激活层)后继续训练,acc基本接近论文的精度。 参考了paddle模型库中关于可分离卷积的写法,最后一步基本都有激活函数,对于轻量级的网络可能用relu/relu6或者hardswish函数实现。关于这两者的差异,目前还不太清楚原因。有明白的大佬希望在评论区留言解惑。 这也许是这次复现的一个很大的收获,关注具体模块的实现方法,平时需要加强源码阅读以及自己多思考问题能力。 总结通过此次论文复现,学到了很多以前没有注意过的知识点,这次论文复现,从论文学习到模型模仿实现,以及模型训练中出现的问题。关于论文复现的缘由,一方面是线下和一些PPDE开发者面基的时候,他们在分享相关的复现经验时候,当时脑中闪现的一个想法:什么时候可以自己复现论文。另一方面其实也想检验一下自己的所学。 这次论文复现也看到自己的一些不足,之前习惯前人的现成模型直接拿来主义,而未进行模型结构实现方面的思考。同时需要多阅读相同模型的实现,上面说到这次论文复现的这个模型,有人在组网的最后一层添加relu,也是参考其他人实现而达到的精度。同时,也可以看看飞桨官方以前提供的成功复现经验进行学习。

0

CNN

flyai会员1644651721·2022-05-06 20:05 0 阅读 148
文章多头自注意力在文本分类
想来至今还没有从0完整实现过Attention,即使公式掌握的足够熟悉,但很多细节的问题,还是要亲自动手实践一次后,才能了解得更清楚。本次我们通过手动实现一个多头注意力的方式,对文本分类做一次实践,加深对Attention机制的理解。在实践过程中,穿插着会提到一些Attention的细节,争取做到代码与论文紧密结合。 实践部分,我们还是选择使用TensorFlow2.1进行建模,由于要尝试构建Attention的模型,所以在建模部分我们主要采用继承keras.Layer的方式分别构建各个模块,并且使用Sequential API的方式将各层连接起来。具体建模过程,请见我的github仓库。本次实践主要基于Shicoder 的代码进行修改。受限于作者能力,如有问题,欢迎在下方留言讨论。 数据准备:本次文本分类任务,我们选取的TensorFlow.keras.datasets自带的IMDB数据集。由于数据集已经是经过处理后的数据,我们只需设定每条句子的最大文本长度后进行训练集和测试集的划分。这里针对数据准备过程中设置的超参数如下: vocab_size = 20000 # 文本中单词词频在前max_features个的词maxlen = 80 # 最大文本长度batch_size = 32位置编码我们认为,对于句子中每个词,Attention机制更容易使得这个词关注到与其相关的其他词,在表现上是要强于传统的CNN和RNN的。但是CNN和RNN有一个优势,就是他们都会关注到句子中词与词之间的顺序问题。RNN自然不必说,如果CNN中的卷积核的长度大于1,那么在一次采样的时候,编码结果能够包含一定词顺序的信息。而Attention本身更多关注的是一个并行的结果,并没有考虑到词与词之间的顺序。对于这种情况,有必要在embeddings的基础上加入位置编码,positional emcodings。每个位置对应于一个编码,位置编码完成后与embeddings的结果直接相加。 假设我们定义embedding的向量维度为128,那么positional emcodings的维度也是128。(在论文中这两个向量维度定义为$d_{model}$,其大小为512)关于位置编码的方式,论文使用三角函数对不同频率的位置进行编码,具体编码公式为: $PE{(pos, 2i)} = sin(pos/10000^{2i/d{model}})$ $PE{(pos, 2i+1)} = cos(pos/10000^{2i/d{model}})$ 对于每个位置,也就是每一个词,使用sin函数或cos函数进行编码,得到的是一个依赖于具体位置的绝对位置的编码。论文中还提到,选择这种编码方式的原因,在于其能够学习到一定程度的相对位置信息。根据三角函数的和差化积公式,对于固定的偏移量$k$,$PE{pos+k}$都可以被表示为$PE{pos}$的线性组合。具体公式可以表示为: $PE(pos+k, 2i) = PE(pos, 2i)PE(k, 2i+1) + PE(pos, 2i+1)PE(k, 2i)$ $PE(pos+k, 2i+1) = PE(pos, 2i+1)PE(k, 2i+1) - PE(pos, 2i)PE(k, 2i)$ 从代码层面看: from tensorflow.keras import layers 首先构建输入层和embedding层输入层中的shape=2D,第0位是batch_size,第1位是max_len,在这种条件下embedding的维度就是 (batch_size, max_len, embedding_dim),其中embedding_dim=128S_inputs = layers.Input(shape=(None,), dtype=’int32’)embeddings = layers.Embedding(vocab_size, 128)(S_inputs)接下来我们开始构建positional emcodings 首先计算三角函数中的分母,根据位置编码公式 使用np.arange(),设置长度为size大小的一半,其中size = d_model默认step=1,np.arange() 会创建一个包含整数序列的一维张量position_j = 1. / tf.math.pow(10000., 2 * np.arange(self.size / 2, dtype=’float32’) / self.size)然后计算分子,分子中主要获取的是位置 其中x是输入位置编码模型的embedding结果,这里选取每个向量的第一个位置,同时在batch_size和max_len的维度上保持不变这个位置下初始化全1的矩阵,然后使用cumsum,在新位置存放之前所有位置的累加和,相当于对每个维度进行位置编号position_i = tf.math.cumsum(tf.ones_like(x[:, :, 0]), axis=1) - 1由于分子和分母可能存在维度不匹配的情况,如果有必要需要对两个编码结果在不同位置进行扩展维度。然后将分子与分母进行矩阵相乘,得到三角函数的输入部分。再将这个输入部分分别通过sin和cos函数,得到的结果在同一维度进行拼接,表示如下: position_ij = tf.matmul(position_i, position_j)position_ij = tf.concat([tf.math.cos(position_ij), tf.math.sin(position_ij)], 2)拼接之后的位置编码与原x,也就是embedding的形状是一摸一样的,之后根据论文中的说法,我们需要将位置编码与embedding进行相加,得到的结果就可以往Attention层送了。 Attention机制首先要明确一下各个变量之间的联系和向量的长度。我们知道,Attention中Q,K,V分别是输入数据,也就是上文的embeddings + positional encodings,乘以各自的参数矩阵得到的结果,并且这些参数矩阵是可以学习的。于是应该先定义Q,K,V对应的参数矩阵。 同时我们需要明确的是,论文中使用了多头注意力multi-head self-Attention,对于每个头,完成Attention的计算后,会将得到的8个头拼接在一起。原始文本的向量长度定义为512,那么每个头下产生的Q,K,V矩阵的输出维度就是 512 / 8 = 64,那么三个权重矩阵W_Q,W_K,W_V的维度就是[512, 64],这样输入数据与参数矩阵的乘积,就会得到向量为 64 的Q,K,V。并且,多头对应的参数矩阵是不一样的,也就是说每个头都有独一无二的一组权重矩阵W_Q,W_K,W_V,正好对应了多头的使用意义,扩展不同的表达子空间(这里可以将不同的表达子空间理解为CNN中卷积核,不同权重的多个卷积核对数据进行多次采样,这样就能够获取更加丰富的表达结果)。 在本次实践中,输入数据的向量长度为128,那么每个头下,三个权重矩阵的输出维度是16。除了与论文中的维度差异外,多头下的权重矩阵维度也有改变。为了避免同时维护不同头下三个权重矩阵,这里选择将权重矩阵的输出维度就设置为输入数据的向量长度128,也就是将不同头下,同一类型的权重矩阵合并为一个,而不是分成8。这样做的好处是不需要同时定义8组权重矩阵,显得代码过于冗长,最后Attention的计算结果也不必进行拼接了,因为就是在8个头的条件下计算的。 def build(self, input_shape): “”” input_shape 是输入数据的维度,这里我们定义输入的数据是上一层编码的结果 input_shape[-1]表示输入数据最后一个维度的大小,也就是embedding_dim,此处设置为128 output_dim 为输出维度,这里是 nb_head * size_per_head 其中,nb_head = 8 表示8个头,size_per_head = 16 表示每个头下的向量维度 三个参数矩阵的维度都是 shape=[embedding_dim, output_dim],也就是 [128, 128] “”” self.WQ = self.add_weight(name=’WQ’, shape=(input_shape[-1], self.output_dim), initializer=tf.random_uniform_initializer(), trainable=True, regularizer=’l2’) self.WK = self.add_weight(name=’WK’, shape=(input_shape[-1], self.output_dim), initializer=tf.random_uniform_initializer(), trainable=True, regularizer=’l2’) self.WV = self.add_weight(name=’WV’, shape=(input_shape[-1], self.output_dim), initializer=tf.random_uniform_initializer(), trainable=True, regularizer=’l2’) super(Attention, self).build(input_shape)参数矩阵完成初始化后,下一步就是通过输入数据乘以各自的参数矩阵得到查询向量Q,键向量K,和值向量V。具体如下(拿查询向量Q的获取为例); Q_seq = tf.matmul(x, self.WQ)Q_seq = tf.reshape(Q_seq, (-1, tf.shape(Q_seq)[1], self.nb_head, self.size_per_head))Q_seq = tf.transpose(Q_seq, perm=[0, 2, 1, 3]) # 为了后续计算方便,这里重新排列张量的轴 重排后的 Q_seq.shape = (batch_size, self.nb_head, seq_len, self.size_per_head)三个向量全部获取完成后,就是根据公式计算Attention了。 $Z = softmax(\frac {QK^T} {\sqrt d_k})V$ 从这个公式中不管怎么看,都感觉Q和K应该是矩阵相乘,但是论文中又明确提出了Scaled Dot-Product Attention这样的概念,于是这里还是选择矩阵内积的方式。在实践RGCN时发现,可能在某种条件下,矩阵乘法和内积得到的效果是一样的。 得到的结果需要经过$\frac {1} {\sqrt{d_k}}$的缩放。采取缩放的原因是作者怀疑过大的$d_k$值容易产生很大的乘积结果,使得softmax的梯度变得很小。为抵消这种情况,需要采取这种缩放方式。 A = tf.multiply(Q_seq, K_seq) / self.size_per_head ** 0.5A = tf.transpose(A, perm=[0, 3, 2, 1])A = self.Mask(A, V_len, ‘add’)A = tf.transpose(A, perm=[0, 3, 2, 1])A = tf.nn.softmax(A)O_seq = tf.multiply(A, V_seq) # softmax的值乘以值向量O_seq = tf.transpose(O_seq, (0, 2, 1, 3)) O_seq.shape = (batch_size, self.nb_head, seq_len, self.size_per_head)O_seq = tf.reshape(O_seq, (-1, tf.shape(O_seq)[1], self.output_dim))mask操作可以看到,在进行softmax之前,可能还需要加入一步mask操作。mask操作的意义有两个。 padding mask在很多NLP任务上,如果文本的原始长度小于我们指定的最大文本长度时,常用的做法是用0将缺失的位置补齐。但从文本语义关系的角度分析,这些位置其实没有意义,我们也不想要这些位置的信息参与到学习过程中。在self-attention中,也不会希望有效词的注意力集中在无意义的位置上。 因此我们希望在训练时将补全的位置给mask掉。通过 padding mask 操作,使得补全位置上的值成为一个非常大的负数,经过softmax层后,这些位置上的概率就是0。此操作就相当于把补全位置的无用信息给遮蔽掉了。 这一步要放在softmax之前,当然没有也是可以的。论文中描述Scaled Dot-Product Attention的图中mask,后面标注了optional。具体的做法可以参考: def Mask(self, inputs, seq_len, mode=’mul’): “”” mask.shape = [batch_size, seq_len] 或 [batch_size, seq_len, 1] :param inputs: :param seq_len: 是一个二维矩阵 :param mode: 可以指定两种不同的mask方式 :return: “”” if seq_len == None: return inputs else: # tf.shape(inputs)[1] 是每个 head 的维度 # 生成的 one_hot 矩阵的维度是 (len(seq_len[:,0]), tf.shape(inputs)[1]) # 这里的 len(seq_len[:,0]) 实际上就是文本长度 seq_len mask = tf.one_hot(seq_len[:, 0], tf.shape(inputs)[1]) # 首先将每行为1的位置之后的所有位置全部置1,然后对角变换,1变0,0变1 # 当前 mask 是一个下三角矩阵,一个角全1,另一个角全0 mask = 1 - tf.math.cumsum(mask, 1) for _ in range(len(inputs.shape) - 2): mask = tf.expand_dims(mask, 2) if mode == 'mul': # 按位相乘,乘以0的元素就变为0 return inputs * mask if mode == 'add': # 乘以0就变为0,乘以1的被变为无穷大,然后元素减去这个无穷大就变成了一个负数 return inputs - (1 - mask) * 1e12 sequence mask这里的mask是比较重要的,需要在Transformer的Decoder中被使用到。Attention本质上会关注到全局的信息,但在执行预测时,不能让其看到当前词后面的词信息,所有有必要将这些词mask掉。这部分属于Transformer的Decoder部分,这里就不细说了。 训练Attention模型搭建完毕后,后续还要构建一个平均池化层和全连接层,然后就可以对模型进行训练了。模型结构如下: Model: “model”Layer (type) Output Shape Param # Connected toinput_1 (InputLayer) [(None, None)] 0embedding (Embedding) (None, None, 128) 2560000 input_1[0][0]position_embedding (PositionEmbedding) (None, None, 128) 0 embedding[0][0]attention (Attention) (None, None, 128) 49152 position_embedding[0][0]position_embedding[0][0]position_embedding[0][0]global_average_pooling1d (None, 128) 0 attention[0][0]dropout (Dropout) (None, 128) 0 global_average_pooling1d[0][0]dense (Dense) (None, 1) 129 dropout[0][0]Total params: 2,609,281Trainable params: 2,609,281Non-trainable params: 0

0

RNN

flyai会员1644651721·2022-05-06 20:05 1 阅读 304
文章山东土地集团杯-遥感图像语义分割
一、山东土地集团杯-遥感图像语义分割 比赛地址:https://www.heywhale.com/home/competition/61c95b5dc4437e0017d5feea/content/0?from=notice 1.大赛背景滨州市按照中央和省相关要求,以智慧城市建设为统领,切实推进数据资源整合,创新开展各类数据应用,建成滨州市公共数据开放网站,实现54个部门单位、7个县(市、区)共11592个目录,约4亿余条数据依法依规向社会开放,覆盖经济、科技、教育、卫生、文化、体育等20余个主题。 本次滨州市“山东土地集团杯”数据应用创新创业大赛旨在进一步提升滨州市大数据应用范围和效果,提高部门和社会大众对大数据的理解和认识,发掘大数据优秀案例和人才,加快数据要素资源与产业发展融合,推动赛事成果转化,培育发展数据产业,推动产数融合,为经济社会发展提供数据支撑,服务经济提质增效升级,真正做到数据取之于民、造福于民,努力实现数据开放、数据应用、产业发展三位一体的目标。 地物要素分类是地表第五要素观测与测绘的重要手段之一,然而目前地物要素的提取方法主要依赖人工,效率低且成本高昂,急需通过先进的算法提高精度并使其自动化。充分运用智能算法与大数据技术突破遥感影像的信息提取与分析瓶颈,不仅是业务端的迫切需要,更是一个企业在数据时代打造数字化业务的重要标杆。 基于赛事官方提供的数据及建模分析平台,参赛者需要对光学遥感图像中各类光谱信息和空间信息进行分析,将遥感图像进行土地类型语义分割处理,为图像中具有语义信息的各个像元赋予语义类别标签。 2.数据描述此次算法赛采用了1.5 万+遥感影像语义分割样本数据,遥感数据为GF1-WFV拍摄的山东滨州附近地区的影像,预处理过程为正射校正、配准、裁剪。分类目标是山东省土地利用类型,经过处理合并得到以下六类:耕地、林地、草地、水域、城乡、工矿、居民用地及未利用土地。 原始影像数据格式为 tif(000001_GF.tif),包含红绿蓝(RGB) 三个波段,影像尺寸为 256*256 标注文件格式为 tif(000001_LT.tif),每个像素的标签值由 1~6 表示: 类别 类别标签耕地 1林地 2草地 3水域 4城乡、工矿、居民用地 5未利用土地 63.数据下载数据名称 数据描述 下载链接(成功报名后可下载) 开放时间提交样例 「results.zip」:提交样例文件,输出值为随机结果,共参赛人员参考 点击下载 2021-12-31中午 12:00初赛训练集 5,000 原始影像和标注文件 点击下载 2021-12-31中午 12:00初赛A榜测试集 2,000 原始影像 点击下载 2021-12-31中午 12:00初赛B榜测试集 1,000 原始影像 点击下载 2022-1-27中午 12:00复赛相关数据 训练集、A榜测试集和B榜测试集 赛事页面↗前往组织-工作台-查看数据源,新建项目通过“添加数据源”选项挂载使用数据 2022-2-15 中午12:00二、环境准备本项目采用paddleseg套件实现了遥感影像地块的分割,paddleseg版本号为v2.3版本 1.PaddleSeg下载In [ ] 下载paddleseg%cd ~!git clone -b release/2.3 https://gitee.com/paddlepaddle/PaddleSeg.git —depth=12.PaddleSeg安装In [ ]%cd ~/PaddleSeg/!pip install -U pip!pip install -r requirements.txt!pip install -e .三、 数据准备1.解压缩数据In [ ]%cd ~ 解压训练数据集到work目录下!unzip -oaq -d /home/aistudio/train_dataset data/data125219/初赛训练集.zip 解压测试数据集到work目录下!unzip -oaq -d /home/aistudio/test_dataset data/data125219/初赛A榜_GF.zip/home/aistudio2.划分出训练集和验证集文件列表In [ ] 生成文件列表文件%cd ~import osimport numpy as npDATA_ROOT_DIR = ‘/home/aistudio/train_dataset/‘ def make_list(): img_list = [img.split(‘.’)[0].strip(‘_GF’) for img in os.listdir(os.path.join(DATA_ROOT_DIR, ‘初赛训练_GF’))] data_path_list = [] for image_id in img_list: image_path = os.path.join(DATA_ROOT_DIR, ‘初赛训练_GF’, f”{image_id}_GF.tif”) label_path = os.path.join(DATA_ROOT_DIR, ‘初赛训练_LT’, f”{image_id}_LT.tif”) data_path_list.append((image_path, label_path)) np.random.seed(5) np.random.shuffle(data_path_list) total_len = len(data_path_list) train_data_len = int(total_len*0.8) train_data = data_path_list[0 : train_data_len] val_data = data_path_list[train_data_len : ] with open(os.path.join(DATA_ROOT_DIR, 'train_list.txt'), "w") as f: for image, label in train_data: f.write(f"{image} {label}\n") with open(os.path.join(DATA_ROOT_DIR, 'val_list.txt'), "w") as f: for image, label in val_data: f.write(f"{image} {label}\n") if name == ‘main‘: make_list()/home/aistudio3.标签修改由于原始label图像是从 1开始编码,不符合PaddleSeg要修,故进行修改。 In [ ] 修改label从0开始起算import numpy as npfrom PIL import Image def convert_img_lab(img_path): img=Image.open(img_path).convert(“L”) img=np.array(img) # 修改label从0开始起算 # 惯性思维用循环了,多谢嘟嘟赐教 img=img-1 # for i in range(256): # for j in range(256): # img[i][j]=img[i][j]-1 img=Image.fromarray(img.astype('uint8')) img.save(img_path,quality=95) In [ ] 开始修改label%cd ~for file in os.listdir(‘/home/aistudio/train_dataset/初赛训练_LT/‘): convert_img_lab(os.path.join(‘/home/aistudio/train_dataset/初赛训练_LT/‘, file))In [ ]%cd ~!head -n 10 train_dataset/train_list.txt/home/aistudio/home/aistudio/train_dataset/初赛训练_GF/003938_GF.tif /home/aistudio/train_dataset/初赛训练_LT/003938_LT.tif/home/aistudio/train_dataset/初赛训练_GF/009635_GF.tif /home/aistudio/train_dataset/初赛训练_LT/009635_LT.tif/home/aistudio/train_dataset/初赛训练_GF/002443_GF.tif /home/aistudio/train_dataset/初赛训练_LT/002443_LT.tif/home/aistudio/train_dataset/初赛训练_GF/010992_GF.tif /home/aistudio/train_dataset/初赛训练_LT/010992_LT.tif/home/aistudio/train_dataset/初赛训练_GF/004967_GF.tif /home/aistudio/train_dataset/初赛训练_LT/004967_LT.tif/home/aistudio/train_dataset/初赛训练_GF/011362_GF.tif /home/aistudio/train_dataset/初赛训练_LT/011362_LT.tif/home/aistudio/train_dataset/初赛训练_GF/001391_GF.tif /home/aistudio/train_dataset/初赛训练_LT/001391_LT.tif/home/aistudio/train_dataset/初赛训练_GF/003704_GF.tif /home/aistudio/train_dataset/初赛训练_LT/003704_LT.tif/home/aistudio/train_dataset/初赛训练_GF/015393_GF.tif /home/aistudio/train_dataset/初赛训练_LT/015393_LT.tif/home/aistudio/train_dataset/初赛训练_GF/004227_GF.tif /home/aistudio/train_dataset/初赛训练_LT/004227_LT.tifIn [ ]from PIL import Imageimg=Image.open(‘/home/aistudio/train_dataset/初赛训练_GF/003938_GF.tif’)print(img.size)img(256, 256) 四、模型训练从数据集分析结果来看,各个类别像素占整个图片的面积比例很小 具体训练配置如下remotesensing.yml batch_size: 60iters: 150000 train_dataset: type: Dataset dataset_root: /home/aistudio train_path: /home/aistudio/train_dataset/train_list.txt num_classes: 6 transforms: - type: ResizeStepScaling min_scale_factor: 0.75 max_scale_factor: 1.5 scale_step_size: 0.25 - type: RandomHorizontalFlip - type: RandomVerticalFlip - type: RandomRotation max_rotation: 30 - type: RandomDistort brightness_range: 0.2 contrast_range: 0.2 saturation_range: 0.2 - type: Normalize - type: Resize target_size: [256, 256] mode: train val_dataset: type: Dataset dataset_root: /home/aistudio val_path: /home/aistudio/train_dataset/val_list.txt num_classes: 6 transforms: - type: Resize target_size: [256, 256] - type: Normalize mode: val optimizer: type: sgd momentum: 0.9 weight_decay: 4.0e-5 lr_scheduler: type: PolynomialDecay learning_rate: 0.01 end_lr: 0 power: 0.9 loss: types: - type: CrossEntropyLoss coef: [1, 0.4] model: type: OCRNet backbone: type: HRNet_W48 align_corners: False pretrained: https://bj.bcebos.com/paddleseg/dygraph/hrnet_w48_ssld.tar.gz backbone_indices: [-1] pretrained: https://bj.bcebos.com/paddleseg/dygraph/ccf/fcn_hrnetw48_rs_256x256_160k/model.pdparams In [ ]%cd ~/PaddleSeg/ !python train.py \ —config ../remotesensing.yml \ —do_eval \ —use_vdl \ —save_interval 100 \ —save_dir output_ocrnet 五、模型预测因为图片后缀为.tif,所以对PaddleSeg/paddleseg/utils/utils.py进行了修改,增加 .tif 格式模型预测时希望将预测的结果直接作为提交结果,但是paddleseg默认预测的结果是增加权重后生成的图片,所以对paddleseg的源码进行了修改。修改的文件为PaddleSeg/paddleseg/core/predict.py,修改后是下面这段代码In [ ] PaddleSeg/paddleseg/utils/utils.pydef get_image_list(image_path): “””Get image list””” valid_suffix = [ ‘.JPEG’, ‘.jpeg’, ‘.JPG’, ‘.jpg’, ‘.BMP’, ‘.bmp’, ‘.PNG’, ‘.png’, ‘.tif’ # 增加tif格式 ] image_list = [] image_dir = None if os.path.isfile(image_path): if os.path.splitext(image_path)[-1] in valid_suffix: image_list.append(image_path) else: image_dir = os.path.dirname(image_path) with open(image_path, ‘r’) as f: for line in f: line = line.strip() if len(line.split()) > 1: line = line.split()[0] image_list.append(os.path.join(image_dir, line)) elif os.path.isdir(image_path): image_dir = image_path for root, dirs, files in os.walk(image_path): for f in files: if ‘.ipynb_checkpoints’ in root: continue if os.path.splitext(f)[-1] in valid_suffix: image_list.append(os.path.join(root, f)) else: raise FileNotFoundError( ‘--image_path is not found. it should be an image file or a directory including images’ ) if len(image_list) == 0: raise RuntimeError('There are not image file in `--image_path`') return image_list, image_dir In [ ] 修改predict函数import osimport math import cv2import numpy as npimport paddle from paddleseg import utilsfrom paddleseg.core import inferfrom paddleseg.utils import logger, progbar, visualize def mkdir(path): sub_dir = os.path.dirname(path) if not os.path.exists(sub_dir): os.makedirs(sub_dir) def partition_list(arr, m): “””split the list ‘arr’ into m pieces””” n = int(math.ceil(len(arr) / float(m))) return [arr[i:i + n] for i in range(0, len(arr), n)] 修改predict函数def predict(model, model_path, transforms, image_list, image_dir=None, save_dir=’output’, aug_pred=False, scales=1.0, flip_horizontal=True, flip_vertical=False, is_slide=False, stride=None, crop_size=None): “”” predict and visualize the image_list. Args: model (nn.Layer): Used to predict for input image. model_path (str): The path of pretrained model. transforms (transform.Compose): Preprocess for input image. image_list (list): A list of image path to be predicted. image_dir (str, optional): The root directory of the images predicted. Default: None. save_dir (str, optional): The directory to save the visualized results. Default: 'output'. aug_pred (bool, optional): Whether to use mulit-scales and flip augment for predition. Default: False. scales (list|float, optional): Scales for augment. It is valid when `aug_pred` is True. Default: 1.0. flip_horizontal (bool, optional): Whether to use flip horizontally augment. It is valid when `aug_pred` is True. Default: True. flip_vertical (bool, optional): Whether to use flip vertically augment. It is valid when `aug_pred` is True. Default: False. is_slide (bool, optional): Whether to predict by sliding window. Default: False. stride (tuple|list, optional): The stride of sliding window, the first is width and the second is height. It should be provided when `is_slide` is True. crop_size (tuple|list, optional): The crop size of sliding window, the first is width and the second is height. It should be provided when `is_slide` is True. """ utils.utils.load_entire_model(model, model_path) model.eval() nranks = paddle.distributed.get_world_size() local_rank = paddle.distributed.get_rank() if nranks > 1: img_lists = partition_list(image_list, nranks) else: img_lists = [image_list] added_saved_dir = os.path.join(save_dir, 'added_prediction') pred_saved_dir = os.path.join(save_dir, 'pseudo_color_prediction') logger.info("Start to predict...") progbar_pred = progbar.Progbar(target=len(img_lists[0]), verbose=1) with paddle.no_grad(): for i, im_path in enumerate(img_lists[local_rank]): im = cv2.imread(im_path) ori_shape = im.shape[:2] im, _ = transforms(im) im = im[np.newaxis, ...] im = paddle.to_tensor(im) if aug_pred: pred = infer.aug_inference( model, im, ori_shape=ori_shape, transforms=transforms.transforms, scales=scales, flip_horizontal=flip_horizontal, flip_vertical=flip_vertical, is_slide=is_slide, stride=stride, crop_size=crop_size) else: pred = infer.inference( model, im, ori_shape=ori_shape, transforms=transforms.transforms, is_slide=is_slide, stride=stride, crop_size=crop_size) pred = paddle.squeeze(pred) pred = pred.numpy().astype('uint8') # get the saved name if image_dir is not None: im_file = im_path.replace(image_dir, '') else: im_file = os.path.basename(im_path) if im_file[0] == '/' or im_file[0] == '\\': im_file = im_file[1:] # 修改预测后的图片标签 # 修改label从1开始起算 # 惯性思维用循环了,多谢嘟嘟赐教 pred=pred+1 # for jj in range(256): # for j in range(256): # pred[jj][j]=pred[jj][j]+1 pred_saved_path = os.path.join(save_dir, im_file.rsplit(".")[0].strip("_GF") + "_LT.tif") mkdir(pred_saved_path) cv2.imwrite(pred_saved_path, pred) progbar_pred.update(i + 1) In [ ] 模型预测%cd ~/PaddleSeg/!python predict.py \ —config ../remotesensing.yml \ —model_path ./output_ocrnet/best_model/model.pdparams \ —image_path /home/aistudio/test_dataset \ —save_dir /home/aistudio/result六、提交整体跑了约30个epoch,打包zip文件夹并提交,即可得分。 如需提分可多花一些时间训练。

1

CNN

flyai会员1644651721·2022-05-06 20:05 0 阅读 175
文章Vision Transformer
Vision Transformer(VIT)TransformerTransformer提出后,注意力机制广泛应用于自然语言处理的各项任务中,并取得了很好的效果。例如,采用Transformer的Encoder结构的Bert在11项自然语言处理任务中达到SOTA,同时还有采用Decoder结构的GPT系列。相较于RNN缺乏处理一个句子中较远距离的两个token,注意力机制能够更有效地进行全局建模以及高效的并行训练。 Transformer的结构如下所示,包含N个Encoder和N个Decoder。每个Encoder包含一个多头注意力层和一个前馈神经网络层,Decoder相较于Encoder多了一个多头注意力层用来进行Encoder的输出和Decoder的输入的交互。 注意力机制注意力机制的表达式如下所示: Attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_k}})V 在自注意力机制中,Q,K,V是相同的,Q表示query,K表示key,V表示value,d_k是Q的维度,softmax的输出是注意力分数。 例如,在不考虑batch的情况下,一个句子包含n个token,词嵌入维度为d_k,经过词嵌入后改句子的shape为 (n, d_k),即Q,K,V为(n,d_k)的张量。QK^T后的shape为(n, n),经过softmax和scale后不改变张量的shape,因此softmax(\frac{QK^T}{\sqrt{d_k}})V的shape为(n, d_k)。即经过Attention层后,输入和输出的shape保持一致。 VIT自AlexNet后,CNN已在计算机视觉领域流行了数十年,Transformer在自然语言处理方向的流行使得大家开始想要将Attention机制应用到CV中。在VIT之前,已经有部分工作尝试使用Attention改进CNN的网络结构,并且取得了不错的效果。 对于一个图像而言,即使是中等分辨率,包含的像素数量也是非常多的,因此采用像素点为单位进行建模在Transformer中是行不通的。VIT采用的方式是将一张图像分成16*16个patch,每个patch相当于nlp中的一个token,然后进行嵌入得到图像的向量表示。 得到嵌入的向量后的处理便和nlp没有什么区别了,VIT采用的是Transformer的编码器结构(如下图所示)。这里需要注意一点,在VIT中,除了图像划分后得到的16*16个patch以外,前面还有一个分类用的patch,因此共有16*16+1个patch。经过嵌入层后的输出的shape为(257, 784),而后是L个Encoder,每一层的输出保持shape不变。最后一层Encoder的输出只取出Class的结果,然后将其放到一个多层感知机进行分类。 VIT在中等数据集上训练并没有相同参数量的ResNet的表现好,但在经过大型数据集预训练后,VIT在大中型数据集上均达到了SOTA。这一点充分说明了Transformer经过预训练后可以有效地处理视觉方向的任务。作者也在原文中提到,VIT需要在大型数据集上进行预训练才能达到较好的效果是因为相较于CNN来说Transformer缺少归纳偏置,因此需要在大规模的数据集上学习来得到归纳偏置的能力。 VIT相较于之前的工作而言,完全抛弃了CNN的结构,使用Pure Transformer进行分类任务。简单来看这项工作可能只是将Transformer原封不动的搬运到图像分类上,但实际上VIT更可以说是尝试打通了NLP和CV的通道,证明了使用同样的模型既可以处理语言又能够处理图像,相当于挖了一个多模态的大坑(从2021年多模态领域的顶刊论文可能看出这一点)。

1

Attention

JerryJiang·2022-05-06 20:05 0 阅读 177
文章pytorch中操作tensor的一些用法
简单记录一下torch对tensor的一些操作,后续有空再完善,具体定义和应用举例请参见reference torch.view()  作用:把原先tensor中的数据按照行优先的顺序排成一个一维的数据,然后按照参数组合成其他维度的tensor。如torch.view(3,2,2)  reference:https://blog.csdn.net/york1996/article/details/81949843 torch.repeat()  作用:对张量进行重复扩充,如(通道重复,行重复,列重复),a.repeat(2,1,1),1代表不扩充  reference:https://blog.csdn.net/qq_34806812/article/details/89388210  https://blog.csdn.net/qq_29695701/article/details/89763168 torch.cat()  作用:拼接张量,使用torch.cat((A,B),dim)时,除拼接维数dim数值可不同外其余维数数值需相同,方能对齐。  reference:https://blog.csdn.net/qq_39709535/article/details/80803003 torch.stack()  作用:沿着一个新维度对输入张量序列进行连接,即增加新的维度进行堆叠。比如dim=0,则连接[a; b; c];若dim=1,则连接{ [ a[0]; b[0]; c[0] ] ; [ a[1]; b[1]; c[1] ] ; … };dim=2,…  reference:https://blog.csdn.net/xinjieyuan/article/details/105205326 tensor中None用法  作用:None可以在所处维度中多一维,如T[None],T[:, None],T[:, :, None]  reference:https://blog.csdn.net/jmu201521121021/article/details/103773501/ torch.clamp()和torch.clamp()  作用:将输入input张量每个元素的值压缩到区间 [min,max],并返回结果到一个新张量。.clamp_()是一个in-place类型,指当在一个tensor上操作了之后,是直接修改了这个tensor。  reference:https://blog.csdn.net/weixin_39504171/article/details/106069230 torch.mean()  作用:torch.mean(tensor, dim=0), dim表示的是沿着dim维度求平均值  reference:https://blog.csdn.net/haoxue2011/article/details/108349166 torch.full()和torch.full_like()  作用:torch.full((3,4), 5),给定一个值fill_value和一个size,创建一个矩阵元素全为fill_value的大小为size的tensor。  reference:https://blog.csdn.net/Fluid_ray/article/details/109855155

0

PyTorch

wilbur·2022-05-06 20:05 0 阅读 146
文章deep_sort源码剖析(1)deep_sort...iou_matching
这是我在csdn上写的文章,现在迁移到这里 论文题目:SIMPLE ONLINE AND REALTIME TRACKING WITH A DEEP ASSOCIATION METRIC 相关博文推荐:https://blog.csdn.net/cdknight_happy/article/details/79731981 GitHub地址:https://github.com/nwojke/deep_sort OK,话不多说正式开始 vim: expandtab:ts=4:sw=4from future import absolute_importimport numpy as npfrom . import linear_assignment def iou(bbox, candidates): “””Computer intersection over union. Parameters ---------- bbox : ndarray A bounding box in format `(top left x, top left y, width, height)`. candidates : ndarray A matrix of candidate bounding boxes (one per row) in the same format as `bbox`. Returns ------- ndarray The intersection over union in [0, 1] between the `bbox` and each candidate. A higher score means a larger fraction of the `bbox` is occluded by the candidate. """ #预测框的左下,右上坐标 bbox_tl, bbox_br = bbox[:2], bbox[:2] + bbox[2:] #多个候选框的坐标 candidates_tl = candidates[:, :2] candidates_br = candidates[:, :2] + candidates[:, 2:] #计算中间重合部分矩形框IOU大小 tl = np.c_[np.maximum(bbox_tl[0], candidates_tl[:, 0])[:, np.newaxis], np.maximum(bbox_tl[1], candidates_tl[:, 1])[:, np.newaxis]] br = np.c_[np.minimum(bbox_br[0], candidates_br[:, 0])[:, np.newaxis], np.minimum(bbox_br[1], candidates_br[:, 1])[:, np.newaxis]] wh = np.maximum(0., br - tl) #求面积 area_intersection = wh.prod(axis=1) area_bbox = bbox[2:].prod() area_candidates = candidates[:, 2:].prod(axis=1) #返回IOU大小 return area_intersection / (area_bbox + area_candidates - area_intersection) def iou_cost(tracks, detections, track_indices=None, detection_indices=None): “””An intersection over union distance metric. Parameters ---------- tracks : List[deep_sort.track.Track] A list of tracks. detections : List[deep_sort.detection.Detection] A list of detections. track_indices : Optional[List[int]] A list of indices to tracks that should be matched. Defaults to all `tracks`. detection_indices : Optional[List[int]] A list of indices to detections that should be matched. Defaults to all `detections`. Returns ------- ndarray Returns a cost matrix of shape len(track_indices), len(detection_indices) where entry (i, j) is `1 - iou(tracks[track_indices[i]], detections[detection_indices[j]])`. """ #创建ID if track_indices is None: track_indices = np.arange(len(tracks)) if detection_indices is None: detection_indices = np.arange(len(detections)) cost_matrix = np.zeros((len(track_indices), len(detection_indices))) for row, track_idx in enumerate(track_indices): #这个if循环我没有搞懂什么意思,知道的小伙伴可以留言告诉我 #linear_assignment是怎么调用INFTY_COST #这个IF语句注释掉后,我没有看到程序有什么变化 if tracks[track_idx].time_since_update > 1: cost_matrix[row, :] = linear_assignment.INFTY_COST continue 计算IOU的cost值,cost越小,IOU越大 bbox = tracks[track_idx].to_tlwh() candidates = np.asarray([detections[i].tlwh for i in detection_indices]) cost_matrix[row, :] = 1. - iou(bbox, candidates) return cost_matrix

0

图像分类

石驰宇·2022-05-06 20:05 0 阅读 141
没有更多了