快手面经
1自我介绍
项目
U-Net
要先从FCN(全卷积网络说起)。FCN是在CNN的基础上把最后分类的过程给换了,也换成了卷积层。
FCN第一个卷积块(卷积层+池化层)后的输出一般是64通道数,图片长和宽都是原来的一半。第二个卷积块之后变成128,图片再次缩小为上一层的1/4,第三个卷积块之后为256通道,图片继续缩小,第四个之后为512通道,图片继续缩小,第五个之后还是512通道,图片已经变成长为原来的1/32,宽为1/32。
然后经过1x1卷积变成类别数的通道。
最好采用FCN-8s的跳级融合,


就是把第五层的输出反卷积。反卷积上采样的方式:


然后就实现了像素级别的语义分割,最后是每一类对应一个颜色。
上采样还有双线性插值,立方插值,反池化等。
反卷积可以用双线性插值初始化。
U-Net
Unet 背景介绍
Unet 发表于 2015 年,属于 FCN 的一种变体,想了解 FCN 可以看我的另一篇 FCN 全卷积网络论文阅读及代码实现 。Unet 的初衷是为了解决生物医学图像方面的问题,由于效果确实很好后来也被广泛的应用在语义分割的各个方向,比如卫星图像分割,工业瑕疵检测等。
Unet 跟 FCN 都是 Encoder-Decoder 结构,结构简单但很有效。Encoder 负责特征提取,你可以将自己熟悉的各种特征提取网络放在这个位置。由于在医学方面,样本收集较为困难,作者为了解决这个问题,应用了图像增强的方法,在数据集有限的情况下获得了不错的精度。
Unet 网络结构与细节
Encoder

语义分割网络 U-Net 详解
如上图,Unet 网络结构是对称的,形似英文字母 U 所以被称为 Unet。整张图都是由蓝/白色框与各种颜色的箭头组成,其中, 蓝/白色框表示 feature map;蓝色箭头表示 3x3 卷积,用于特征提取;灰色箭头表示 skip-connection,用于特征融合;红色箭头表示池化 pooling,用于降低维度;绿色箭头表示上采样 upsample,用于恢复维度;青色箭头表示 1x1 卷积,用于输出结果。
可能你会问为啥是 5 层而不是 4 层或者 6 层,emmm,这应该去问作者本人,可能对于当时作者拿到的数据集来说,这个层数的表现更好,但不代表所有的数据集这个结构都适合。我们该多关注这种 Encoder-Decoder 的设计思想,具体实现则应该因数据集而异。
Encoder 由卷积操作和下采样操作组成,文中所用的卷积结构统一为 3x3 的卷积核,padding 为 0 ,striding 为 1。没有 padding 所以每次卷积之后 feature map 的 H 和 W 变小了,在 skip-connection 时要注意 feature map 的维度(其实也可以将 padding 设置为 1 避免维度不对应问题),pytorch 代码:
nn.Sequential(nn.Conv2d(in_channels, out_channels, 3),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True))
上述的两次卷积之后是一个 stride 为 2 的 max pooling,输出大小变为 1/2 *(H, W):
语义分割网络 U-Net 详解
pytorch 代码:
nn.MaxPool2d(kernel_size=2, stride=2)
上面的步骤重复 5 次,最后一次没有 max-pooling,直接将得到的 feature map 送入 Decoder。
Decoder
feature map 经过 Decoder 恢复原始分辨率,该过程除了卷积比较关键的步骤就是 upsampling 与 skip-connection。
Upsampling 上采样常用的方式有两种:1. FCN 中介绍的反卷积;2. 插值。这里介绍文中使用的插值方式。在插值实现方式中,bilinear 双线性插值的综合表现较好也较为常见 。
双线性插值的计算过程没有需要学习的参数,实际就是套公式,这里举个例子方便大家理解(例子介绍的是参数 align_corners 为 Fasle 的情况)。
例子中是将一个 2x2 的矩阵通过插值的方式得到 4x4 的矩阵,那么将 2x2 的矩阵称为源矩阵,4x4 的矩阵称为目标矩阵。双线性插值中,目标点的值是由离他最近的 4 个点的值计算得到的,我们首先介绍如何找到目标点周围的 4 个点,以 P2 为例。
第一个公式,目标矩阵到源矩阵的坐标映射:

为了找到那 4 个点,首先要找到目标点在源矩阵中的 相对位置,上面的公式就是用来算这个的。P2 在目标矩阵中的坐标是 (0, 1),对应到源矩阵中的坐标就是 (-0.25, 0.25)。坐标里面居然有小数跟负数,不急我们一个一个来处理。我们知道双线性插值是从坐标周围的 4 个点来计算该坐标的值,(-0.25, 0.25) 这个点周围的 4 个点是(-1, 0), (-1, 1), (0, 0), (0, 1)。为了找到负数坐标点,我们将源矩阵扩展为下面的形式,中间红色的部分为源矩阵。
我们规定 f(i, j) 表示 (i, j)坐标点处的像素值,对于计算出来的对应的坐标,我们统一写成 (i+u, j+v) 的形式。那么这时 i=-1, u=0.75, j=0, v=0.25。把这 4 个点单独画出来,可以看到目标点 P2 对应到源矩阵中的 相对位置。

这里需要注意的是 ,FCN 中深层信息与浅层信息融合是通过对应像素相加的方式,而 Unet 是通过拼接的方式。
那么这两者有什么区别呢,其实 在 ResNet 与 DenseNet 中也有一样的区别,Resnet 使用了对应值相加,DenseNet 使用了拼接。 个人理解在相加的方式下,feature map 的维度没有变化,但每个维度都包含了更多特征,对于普通的分类任务这种不需要从 feature map 复原到原始分辨率的任务来说,这是一个高效的选择;而拼接则保留了更多的维度/位置 信息,这使得后面的 layer 可以在浅层特征与深层特征自由选择,这对语义分割任务来说更有优势。
小结
Unet 基于 Encoder-Decoder 结构,通过拼接的方式实现特征融合,结构简明且稳定,如果你有语义分割的问题,尤其在样本数据量不大的情况下,十分推荐一试。
https://www.cnblogs.com/DOMLX/p/9780786.html
YOLOv4 tiny

GAN
学习https://blog.csdn.net/Sakura55/article/details/81514828?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159661342719195264529311%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159661342719195264529311&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-9-81514828.pc_ecpm_v3_pc_rank_v3&utm_term=GAN&spm=1018.2118.3001.4187




GAN的训练有点像EM,先固定生成器去优化判别器,让判别器把数据集当作正样本,G产生的为负样本。然后固定判别器,去优化G的参数,让G生成的图像经过D的得分尽量高。重复,这个过程不断的让D和G进化。
D学习的条件分布P(Y|X)也就是在X的条件下,Y标签(好坏的分布)。
G学习的是P(X,Y)。
这样的对抗训练方式可能导致不稳定,G的参数梯度更新来自于D,所以G生成的好不好是看D的结果的。G根据D的反馈不断地改进自己的参数,但是如果某一次G产生的图像并不好,但是D给了很高的评价,那么这样G就会朝着错误的方向优化。
GAN使用的是JS散度作为loss。
c-GAN




这个可以不仅要求G的生成好,还要和C足够接近。
这样的思想是从小到大。

图片输入G应该有个encoder,然后把encoder的结果和z相加或者concat。













中心有CycleGAN的影子。










GAN的理论















很像EM。





拿过去的G一起训练效果可能更好。












WGAN











这是利用了1-李普希思条件的等价条件做一个有约束的优化。



这里假设如果图像质量很好,那么encoder和decoder的结果应该查相差不大。

margin也是可以变化的。












增加training data。















训练GAN
.规范化输入
将输入图片规范化到-1到1之间
生成器最后一层的输出使用tanh激活函数
毋庸置疑规范化是最重要的,未经处理的图片是没有办法收敛的。图片规范化一种简单的方法是(images-127.5)/127.5,然后送到判别器去训练,同理生成的图片也要经过判别器,所以生成器的输出也是-1到1之间(和原图的区间范围保持一致)
这里有一个坑,因为生成的图是-1到1之间,需要再经过处理回到0-255区间才能正常显示。经过测试matplotlib似乎没法显示-1-1的图,而scipy.misc可以,所以写GAN我通常结合scipy.misc来看结果。
2.用修正的损失函数
在GAN论文里用min (log 1-D)来优化G,实际上max(log D)更好
实际代码中用反转标签来训练G更方便,即把生成图片当成real的标签来训练
损失函数恐怕是一个超级热门的研究点,参照当前的研究进展,很多实验中已经很少用到上面提到的交叉熵损失了,因为效率实在太低而且不稳定。下面列一下代表性的模型:
DCGAN
最初版本,使用了交叉熵损失,各种GAN玩法的鼻祖,直到目前效果依然很棒。
项目地址:carpedm20/DCGAN-tensorflow
WGAN
使用了Wasserstein损失,去掉了判别器最后一层的sigmoid和log,直接优化Wasserstein距离,但是WGAN需要对判别器做Weight Clip,比较麻烦,而且不能用动量优化(包括momentum和Adam),通常使用RMSProp来优化WGAN
项目地址:Zardinality/WGAN-tensorflow
Least Squares GAN
最小二乘GAN,把生成样本和真实样本分别编码为a,b,优化D的目标函数就是
优化G的目标函数
优化器还是建议RMSProp,其中a,b,c的值要自己设置,具体参考论文或者代码。
项目地址:GunhoChoi/LSGAN_TF
Improved WGAN
我所了解到的最新的一个版本,用一个改进的基于梯度惩罚的loss替代WGAN中的Weight Clip,从而产生比WGAN更高质量的样本,这个loss是可以用Adam来优化的。
项目地址:igul222/improved_wgan_training
3.使用一个具有球形结构的随机噪声z
不要使用均匀分布,而是从高斯分布中采样
Tom White的论文Sampling Generative Networks,项目代码https://github.com/dribnet/plat中查看更多的细节
这一点个人感觉大家都是这么做的,也没有很多可改进的地方。具体等我看了上面这篇论文再来补充。
4.BatchNorm
一个mini-batch里面必须保证只有Real样本或者Fake样本,不要把他们混起来训练
尽可能使用batchnorm,如果限制了不能用,则用instance normalization
个人感觉,这一点很重要。没有加BatchNorm,是造成很多新手训练GAN失败的罪魁祸首,之前我就因为没有按照标准的结构去定义GAN网络结构而吃尽了苦头。
5.避免引入稀疏梯度:ReLU,MaxPool
GAN的稳定性会因为引入稀疏梯度受到很大影响
尽量使用LeakyReLU作为激活函数
对于下采样,使用:Average Pooling或者Conv2d + stride
对于上采样,使用:PixelShuffle或者ConvTranspose2d + stride
PixelShuffle的原文:[1609.05158] Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network
这一点同样是小白容易掉的坑,我这里强烈建议使用全卷积,避免使用任何pooling,因为使用pooling会损失信息,这对于GAN训练很不好。当然如果计算资源不够,该用pooling还是要用的。
6.使用Soft和Noisy的标签
Label平滑,也即如果你设Real=1,Fake=0,那么可以改动一下,对于real,我们可以用一个0.7-1.2之间的随机值来代替,对于fake,用0-0.3这个区间
例如用real batch训练D的时候,不要一次性都给标签1,设一个小概率翻转,也就是会有很小一部分为0,当然这些标签是噪声。
这个技巧我用的比较少,似乎大家用的也都不多。可以试试对比一下效果
7.尽量使用Adam优化器
Adam的优化效率对于GAN来说很显著
前提是能用则用,除非像WGAN那样,规定不能使用,才考虑替换
8.早早的追踪到训练失败的信号
例如D的loss稳定下降,变得很小,或者稳定上升,变得很大。这些都是网络没有balance的信号
这一点其实更需要自己实际训练当中的经验,而且每个人的习惯不一样,我就比较喜欢在一定epoch的时候,输出generated image到路径看一看,一般看到全是噪声,基本可以停止训练了,再往下训练也不会有改善。所以不要把时间浪费在无谓,病态的梯度更新上。
9.训练和测试阶段,在G中使用DropOut
使用DropOut也是为了引入一定的噪声
在生成器的某几层中使用DropOut,而且测试和训练阶段都要做
常规的Dropout是测试阶段关闭的,而GAN里面,测试阶段同样也要使用Dropout
10.如果你有类别标签,请使用它们
如果你还有图片的类别标签,训练判别器在判别真伪的同时对其分类
这又是一个研究领域,主要做的是利用数据和标签,有监督或者半监督的生成指定某一类的数据,相关的有ACGAN,TripleGAN等等。
还有一些做图像Attribute的替换,比如男变女,有胡子变没胡子,也会涉及到这个。看过这方面的论文比较多,方法也比较杂,等我回去整理一下再给大家列举。
http://www.dataguru.cn/article-14458-1.html
GAN->DCGAN
cGAN-ACAGN
LSGAN
WGAN->WGAN-GP (westerstein散度)
CycleGAN
EBGAN->loss senetive GAN
RCNN发展史
RCNN :selective search+backbone(vgg)+svm分类+框回归
Fast-RCNN:seleactive search+backbone+分类回归(ROI Pooling,借鉴SPP-Net)
Faster RCNN RPN+backbone(Resnet50)+分类回归(Roi pooling 为7x7\,提出了anchor box)约等于RPN+Fast RCNN。
RPN输出是confidence_prob和四个调整参数,调整之后的为proposal region。然后要NMS,获得置信度最高的,如果IoU太大,那么可能为一个框。
loss是分类的CE加上回归框调整的smooth L1loss。
Faster RCNN对于小物体效果不好,因为只用到了最后一个特征层。
一般一个网格9个anchor box
输入短边为600,网格为38x38。
SSD:多尺度的特征图的多种anchor box预测。
YOLOv3
相比SSD,加了特征金字塔
backbone(Darknet53)
输入416x416
三个尺度13x13,26x26,52x52。
每个cell的anchor box数量为3。
每个物体的中心由左上的网格负责预测。
区分正样本负样本方法:
IOU判断
最大的IOU。
Mask-RCNN:实例分割方法,把最后的预测box传如一个分割网络即可,以获得像素级别的分类。





CSPNET





CIoU代替Smooth_L1的loss。
one-stage和two-stage的比较
IoU手写,python
def calculateiod(rec1,rec2):
"""
rec1=[l1,r1,t1,b1]
rec2类似
"""
l=max(rec1[0],rec2[0])
r=min(rec1[1],rec2[1])
t=max(rec1[2],rec2[2])
b=min(rec1[3],rec2[3])
if r<l or b <t:
reuturn 0
else:
a=(r-l)*(b-t)
b=(rec1[1]-rec1[0])*(rec1[3]-rec1[2])+(rec2[1]-rec2[0])*(rec2[3]-rec2[2])-a
return a/b
CNN网络参数计算
输入128x64x64,3x3的卷积核,输出512x32x32。
weight的数量为128x3x3x512。
共有512种特征图。
算法题
给出正整数n,求连续的数的和为n的所有组合。
在这里插入代码片/*
* @Author: lenovouser
* @Date: 2020-08-05 18:17:20
* @Last Modified by: lenovouser
* @Last Modified time: 2020-08-05 18:28:02
*/
#include <iostream>
#include <string>
#include <cstdlib>
#include <cmath>
#include<ctime>
#include<vector>
using namespace std;
int main(int argc, char const *argv[])
{
unsigned int n;
cin>>n;
unsigned int min1=1,max1=1;
while(min1<n/2+1)
{
unsigned int sum=(min1+max1)*(max1-min1+1)/2;
if (sum==n)
{
cout<< min1 <<" "<<max1<<endl;
min1+=1;
max1+=1;
}
else
{
if (sum<n)
{
max1+=1;
}
else
{
min1+=1;
}
}
}
return 0;
}
算法复杂度O(n^2)。
更多推荐



所有评论(0)