范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

卷积神经网络中的傅里叶变换1024x1024的傅里叶卷积

  卷积神经网络 (CNN) 得到了广泛的应用并且事实证明他是非常成功的。但是卷积的计算很低效,滑动窗口需要很多计算并且限制了过滤器的大小,通常在 [3,3] 到 [7,7] 之间的小核限制了感受野(最近才出现的大核卷积可以参考我们以前的文章),并且需要许多层来捕获输入张量的全局上下文(例如 2D 图像)。图像越大小核的的表现就越差。这就是为什么很难找到处理输入高分辨率图像的 CNN模型。
  有一种方法可以将核大小扩展到 [1024,1024] 及以上,并且这种方法可以增加给定输入分辨率的核大小并且对推理时间几乎没有影响,还可以大幅降低特征图的空间维度,并且不会丢失几乎任何信息,你相信吗?
  所有这些特征都基于一个简单的数学性质:傅里叶变换的卷积定理(准确地说是互相关定理),卷积的问题
  让我们回顾一些基础知识。 卷积是应用于两个函数的数学运算。 让我们从一维案例开始:
  连续一维卷积
  离散一维卷积
  换句话说:取两个信号,保留一个然后围绕坐标轴翻转另一个信号。 将固定信号上的翻转信号从负无穷移动到正无穷(或直到信号的所有非零部分都已重叠)。 对于每一步计算元素乘积并对所有值求和。 结果值就是此步骤的卷积结果。
  但是为什么我之前提到了互相关呢? 那是因为卷积和互相关实际上是相以同的方式计算的,唯一的区别是过滤器(核)被翻转了。 这由不同的符号表示:
  TensorFlow 和 PyTorch 实际上是在计算输入信号和可学习卷积核的互相关,而不是卷积本身。由于卷积核是由网络学习的,因此卷积核是否翻转并不重要。网络会自己弄清楚什么是最好的结果。框架甚至可以节省一些计算而不进行翻转操作。但是有一个区别,如果卷积核是固定的,当你加载一个训练好的模型时,应该知道它是使用互相关还是卷积训练的,因为需要知道最终是否翻转的权重。
  上面说的主要总结为两个问题:计算输出序列中的单个点需要进行大量计算。输入信号越大(即图像的分辨率越高),核必须更频繁地移动,因此需要更多的计算。同样适用于大核。
  更多的计算意味着更多的内存和更大的计算延迟。 CNN在较低的输入分辨率和更小的过滤器。更少的像素意味着更少的细节,更小的过滤器会导致更小的感受野。网络需要有多个连续的卷积层,以增加感受野。网络变得更深,这再次在训练期间带来了新的挑战。
  二维离散傅里叶变换
  从数学上讲,时间变量 t 的实数或复数函数 x(t) 的傅里叶变换是实数频率变量 f 的复数函数 X(f):
  也可以说我们将信号从时域投影到频域。 通过这样做可以受益于傅里叶变换的特殊性质,即卷积定理和相关定理。
  卷积定理
  互相关定理
  这些概念非常重要也是本文的基础:时域中的卷积/相关对应于频域中的简单元素乘法。但这有什么用的呢?如前所述,卷积需要很多计算,尤其是对于大像素图像和大核。它的复杂性与序列长度成二次方,即 O(N²)。根据卷积定理,我们只需要对变换后的输入和变换后的核进行逐元素的乘法。并且计算傅里叶变换的高效算法,即快速傅里叶变换 (FFT)可将复杂度降低到 O(N log(N))。而且更重要的是只要核比输入信号小,那么计算的复杂度就是恒定的。所以核大小是 [3,3] 还是 [1024, 1024] 并不重要。
  傅里叶变换也适用于实数或复数离散信号 x[k],它分配实变量 n 的复数离散信号 X[n]:
  一维卷积
  二维卷积
  离散傅里叶变换 (DFT) 是用于数字信号处理,而计算机以离散值存储信号。所以在使用 DFT 时,我们需要记住:假设输入信号是周期性的,并且对整个周期进行采样产生的频谱是周期性的
  图像可以解释为空间信号而不是时间信号。 在计算机上图像是空间离散的,因为值存储在像素中这些像素从具有空间分布单元的图像传感器采样而被数字化。
  二维 DFT(以及 2D 连续傅里叶变换)可以分成连续的 1D DFT,其中行和列可以分别计算。
  这有两个优点:首先,可以重用 1D DFT 的算法;其次,它有助于为 2D DFT 建立直觉,因为可以单独解释行和列。
  但离散傅里叶变换有一个小细节:卷积定理不适用于 DFT。两个信号的 DFT 相乘对应于它们的循环卷积,由运算符   表示,而不是它们的线性卷积。
  上图为DFT的循环卷积定理公式
  循环卷积是一个以信号长度 N 的重复周期性信号,而线性卷积的长度为 (N+F-1),其中 F 是滤波器信号(核)的长度。因此如果盲目地在频域中取乘积,会将长度为 (N+M-1) 的信号压缩到长度 N。它可以被视为时域中的混叠,从而在最终结果中产生不希望的伪影。但是循环和线性卷积会共享的值,即 (N-F+1)。而剩余的 (F-1) 值被包裹并干扰信号的其他值。
  如果包裹干扰的值为零,这不就意味着没有干扰了吗?我们可以从循环卷积重建线性卷积。当用至少 (F-1) 个零填充信号时,包裹的值就不会干扰实际值。我们可以循环地将包裹的值移回其位置并裁剪填充的值。
  现在我们已经介绍了理论,让我们看看一些 2D 傅里叶变换并加强我们对 2D 傅里叶变换的理解。基本测试信号及其对 CNN 的影响
  考虑一个像素强度遵循对角正弦波的图像。可以通过沿图像的每个轴将 2D 傅里叶变换分离为多个 1D 傅里叶变换来计算 2D 傅里叶变换。 如果沿着水平轴行走,就会遇到重复的图案。 如果沿着垂直轴行走,情况也是如此。 因此在第四象限(右下),即频率分量为正的象限,很自然地会期望频谱有一个高值。
  注:二维幅度谱通常在绘制时使用对数函数进行缩放,无论图像内容如何图像都具有高偏移量,因为它们通常以无符号整数表示,仅表示正值。
  现在,让我们考虑一个具有不同边长的矩形的输入图像。 如果再次沿着每个轴行走,会遇到一个在水平轴上具有短脉冲宽度的矩形和一个在垂直轴上具有较宽脉冲宽度的矩形。 如果熟悉信号理论,会立即想到的频谱具有某种 sinc 函数,其中 sinc(x)=sin(x)/x。
  如果你想到的是一个 sinc 函数,那么你是完全正确的。频谱由沿两个轴的 sinc 函数组成。在这里可以做一个基本的观察:水平轴有更高的频率分量作为垂直轴,零交叉在水平轴上更分散。这里有两个含义:输入图像中的窄空间特征在幅度谱中具有高频分量,因此它们具有高带宽。高带宽滤波器容易产生噪声。光谱与输入图像中特征的空间长度成反比。窄特征导致宽谱,宽特征导致窄谱。
  这对我们的带有小核的 CNN 意味着什么,比如 3x3 像素?根据我们上面的观察,这应该意味着具有小核的 CNN 充当高带宽滤波器,因此容易产生输入噪声。核尺寸越大,滤波器的带宽越低,选择性越强。图像的二维 DFT 和频域滤波
  我们已经讨论了一些基本信号,现在让我们研究真实图像的 2D DFT。
  频谱的中心代表零频率,也称为偏移。 离中心越远,输入中的频率分量就越高。 考虑到这一点,可以轻松导出高通滤波器和低通滤波器。
  高通滤波器抑制低频并保留高频分量。 这种行为可以通过一个滤波器来实现,该滤波器在近中心的值设为0,而将远离中心的值设为1。滤波器的作用是将滤波器与频谱相乘,然后计算傅里叶反变换。
  如上图所示,高通滤波器可以用作边缘检测器。 图像中的边缘以像素值的突然变化为特征,因此具有高梯度。 梯度越高,涉及的频率越高。
  另一方面,低通滤波器抑制高频分量并保留低频分量。 低通滤波器可以通过在中心区域为 1 而在外部区域为 0 的掩码来实现。
  低通滤波后的图像会变得模糊清晰度降低,计算机视觉中使用的一种典型滤波器是高斯滤波器。它也是一个低通滤波器,但是它并不是突然截止频率,而是会随着频率的升高而逐渐增,所以会使图像平滑。
  上图的图像模糊,但失真较小。 并且看起来更平滑。
  用于机器学习应用的一个非常有趣的核是矩形核。 卷积神经网络通常会逐渐减小空间宽度并增加通道数。 池化,例如最大池化或平均池化通常用于减小空间宽度。 如果我们在频域中进行池化是如何操作的呢?
  通过在频域中应用矩形滤波器,我们可以大幅去除频率分量,而不会对空间域中的图像质量产生很大影响。
  DFT 对于实际输入有一个有趣的特性:它关于原点是共轭对称的。 对称性意味着频谱包含在计算过程中可以省略这样可以进一步加快计算。 下图显示了这种变换及其从频谱重建的图像。
  TensorFlow 中的实现
  上面介绍了使用离散傅里叶变换实现线性卷积的理论知识。下面我们进行实际操作
  我们需要完成以下 6 个步骤:填充输入图像以避免时域中的混叠将滤波器填充到图像大小准备逐元素乘法计算输入图像和滤波器的 2D rFFT转换后的输入和转换后的过滤器的元素乘法计算滤波输入的 2D 逆 rFFT 以获得循环卷积从循环卷积重构线性卷积
  1、填充输入图像
  为了避免时域中的混叠效应,我们需要用至少 (F-1) 个零填充图像,其中 F 是滤波器的边长。 此外计算 DFT 的 FFT 算法对于 2 次方的信号长度(例如 128,512,1024)特别有效。
  填充输入图像至少有两个选项:1、手动填充图像。 2、将 FFT 的序列长度设置为填充信号的长度。
  下面的代码手动填充图像。def GetImagePadding(filterSize): """ returns the one sided padding to pad an image. """ return int((filterSize-1)/2) def FillImageShapeToPower2(imageShape): """ fills the image shape to the next higher power of 2 value. imageShape: Expected to be of shape [batch, channels, height, width] """ width = imageShape[-1] log2 = np.log2(width) newPower = int(np.ceil(log2)) newShape = 2**newPower newShape = (imageShape[0],imageShape[1],newShape,newShape) return newShape def PadImage(image, filterShape): """ returns a padded image considering the size of the filter and the next higher power of 2 value """ input_shape = tf.shape(image) paddingFilter = GetImagePadding(filterShape[0]) finalShape = FillImageShapeToPower2(input_shape+(0,0,2*paddingFilter,2*paddingFilter)) final_padding = int((finalShape[-1]-input_shape[-1])/2) paddings = [[0,0], [final_padding,final_padding], [final_padding,final_padding], [0,0], ] image_padded = tf.pad(image,paddings) return image_padded
  下面是我在计算 FFT 时指定更高序列长度的首选方法:# image is of shape [b,c,h,w] padding = GetImagePadding(filter_shape[0])  image_shape = (input_shape[0], input_shape[1], input_shape[2]+2*padding, input_shape[3]+2*padding)image_shape = FillImageShapeToPower2(image_shape) F_image = tf.signal.rfft2d(image, fft_length=[image_shape[-2],image_shape[-1]])
  2、将滤波器填充到图像大小
  由于需要计算变换后的图像与变换后的滤波器的元素乘积,因此我们需要在计算傅里叶变换之前将滤波器用零填充填充图像。通过正确设置 FFT 计算的 fft_lenght 参数来填充滤波器,即F_filter = tf.signal.rfft2d(filter, fft_length=[image_shape[-2],image_shape[-1]])
  3、计算 2D rFFT
  准备好输入信号后,可以计算填充图像和填充滤波器的 FFT:# Image shape [b,c,h,w], Filter shape [out, in , k, k] F_image = tf.signal.rfft2d(image, fft_length=[image_shape[-2],image_shape[-1]]) F_filter = tf.signal.rfft2d(filter, fft_length=[image_shape[-2],image_shape[-1]])
  利用实际输入的共轭对称性,仅使用 rfft2d 计算 2D 信号的实际 FFT。 输入未填充的信号并将 fft_length 设置为大于输入长度的值。 这会自动用零填充信号。
  提示:TensorFlow 的 rfft2d 实现在输入的最后两个维度上计算 FFT。 与 numpy 的实现不同,并且不能通过参数更改维度。 因此图像的形状是 [batch, channel, height, width],滤波器的形状是 [output_filter, input_filter, kernel_height,kernel_width]
  如果我们是在频域中实现卷积,这样的工作就完成了。 由于TensorFlow实际上是使用的互相关,所以需要对变换后的滤波器进行共轭以获得一致的结果:F_filter = tf.math.conj(F_filter)
  4、元素乘法
  如果我们只有一个图像和一个核,那么逐元素乘法将只是 F_image*F_filter。 但在实际场景中,通常以批处理的形式处理多个图像,并且并行应用多个核。 所以需要重新排列输入信号的维度,并利用数组广播来执行此操作,这样不涉及循环操作。@tf.function def ElementwiseProduct(a, b): """ calculates the elementwise product multiple times taking advantage of array broadcasting.  Is slower as the matrix multiplication, but requires less memory! """ a = tf.einsum("bihw->bhwi",a) a = tf.expand_dims(a,-1) #[b,h,w,in,1] b = tf.einsum("oihw->hwio",b) #[h, w, in, out]  c = a*b #[b,h,w,in,out] due to broadcasting c = tf.einsum("bhwio->bohwi",c) c = tf.math.reduce_sum(c, axis=-1) #[b, out, h, w] return c
  TensorFlow 的 einsum() 函数可用于重塑维度。 箭头左侧的字符描述输入形状,右侧的字符描述输出形状。 图像和过滤器的尺寸进行重新对齐,当计算元素乘积时,所有批次和所有输出过滤器都将被广播。 在乘法之后,通过重新重塑维度和减小输入滤波器的维度来恢复初始形状。
  5、计算2D 逆 rFFT
  逆 FFT 具有与 FFT 相同的 fft_length 参数:out = tf.signal.irfft2d(filterd_image, fft_length=[image_shape[-2],image_shape[-1]])
  6、循环卷积重建线性卷积#Circular shift out = tf.roll(out,shift = [2*padding,2*padding],axis = [-2,-1])  #Truncation out = tf.slice(out,  begin = [0, 0, padding, padding],  size=[input_shape[0],  filter_shape[-1],  input_shape[2],  input_shape[3]] )
  所有步骤就完成了,下面的代码汇总了整个实现:def CalcDFT2D(image, filter): """ Calculates the cross-correlation in the Frequency domain image: [batch, channel, height, width] filter: [height, width, inp_filter, out_filter] """ # 0. Preprocess Inputs input_shape = tf.shape(image) #[batchsize, im_channel, im_height, im_width] filter_shape = tf.shape(filter) #[kernel_H, kernel_W, inp_filter, out_filter] filter = tf.einsum("hwio->oihw",filter) # [kernel,kernel,inp_filter,out_filter]->[out_filter, inp_filter, kernel, kernel]  # 1. & 2. Pad image and Filter:  # Required to avoid aliasing in spatial domain: circular convolution # calculates padding which is used to update image shape. Padding happens during FFT by setting fft_length  padding = GetImagePadding(filter_shape[0])  image_shape = (input_shape[0],input_shape[1],input_shape[2]+2*padding,input_shape[3]+2*padding) image_shape = FillImageShapeToPower2(image_shape) # 3. Fourier Transform image and filter F_image = tf.signal.rfft2d(image, fft_length=[image_shape[-2],image_shape[-1]]) F_filter = tf.signal.rfft2d(filter, fft_length=[image_shape[-2],image_shape[-1]]) F_filter = tf.math.conj(F_filter) #to be equvivalent to the cross correlation # 4. Apply filter by elementwise Multiplication filterd_image = ElementwiseProduct(F_image,F_filter) # 5. inverse DFT on filtered image out = tf.signal.irfft2d(filterd_image, fft_length=[image_shape[-2],image_shape[-1]])  # 6. Reconstruct linear convolution from circular convolution out = tf.roll(out,shift = [2*padding,2*padding],axis = [-2,-1])  out = tf.slice(out, begin = [0, 0, padding, padding], size=[input_shape[0], filter_shape[-1], input_shape[2], input_shape[3]])  return out验证
  我们这写操作这真的有用吗?让我们来验证一下
  首先,我们将查看两个函数(tf.nn.conv2d()和我们的实现)在不同的核大小中的执行时间(以秒为单位)。
  2D卷积的执行时间随着核大小的增加而不断增长。而2D DFT卷积在执行时间上是恒定的,与滤波器的大小无关。这是因为滤波器被填充到图像的大小。如果滤波器更大,则填充的值可以更少。
  现在让我们来看看结果的差异。我们在720x720像素的图像上应用一个3x3大小的核函数,并使用8个核。通过两种算法运行它,并计算绝对差的平均值和标准差。convResult = CalcConv(image, filter) dftResult = CalcDFT2D(image, filter) error = tf.math.abs(convResult-dftResult) mean = tf.math.reduce_mean(error) std = tf.math.reduce_std(error) # Mean Absolute Error: 0.001560982083901763 # Standard deviation: 0.0015975720016285777
  均值和标准差都很低。这种差异来自于数字的不准确性。当观察滤波后的图像及其对应的振幅谱时,我们可以看到它们是基本是一致的。
  直接比较滤波后的图像和二维光谱。
  2D线性卷积结果
  2D DFT卷积结果结论
  本文介绍了卷积和DFT背后的数学理论,通过观察不同的光谱获得了一些想发,并且通过TensorFlow进行了实现,并验证了结果的正确性。
  本文的设计在频域而不是空间域工作的,可能还不完善但是却给出了一些新的想法,特别是对于大输入图像和大尺寸核的处理上。在使用频域似乎有违现有的理论,但实际上可以加快计算速度。
  作者:Sascha Kirch

霍学文丰富完善特色金融体系让北京银行成企业全生态合作平台2022新京智库春季峰会。图新京报在数字化时代变局中,唯有变化才是不变的,唯有积极求变,才能适应时代变化。当前这句对于已成立26年的国内城商行领头羊北京银行而言,尤显特别。北京银行京城古迹北大燕园中的名园往事燕园是北京大学校园的别称,园中有碧波荡漾的未名湖,有一枝独秀的博雅塔,山明水秀,造化所钟。明清时期,这里先是京郊著名的文人私园与皇亲府邸,继而成为尊贵的帝王园囿与皇家赐园。民国时期近期正在热播的六部电视剧,题材各异,各有特色,你在追哪一部?天气进入五月底后,已经能够明显感受到夏天炎热气息的侵袭了,虽然很不喜欢燥热的感觉,但是想到冰镇西瓜和冰镇饮料还有风扇,街上形形色色的悦目夏日穿着,心里又止不住地期待对于期盼的夏天,带你云旅游,绝美地下世界,自然的鬼斧神工与人文的巧夺天工太空与海底,一直是人们未能完全探索的地方,有着无数的秘密等着我们去发掘。而在人们常忽略的地底世界,也有许多壮观的美景。一起来领略这些绝美的地下景色吧大自然的鬼斧神工地下溶洞喀斯特地城市夜景亮化工程是越亮越好吗?城市夜景亮化工程是城市基础设施建设的一部分,也是城市发展繁荣的体现。但随着市场的扩大,管理难度加大,使得整个照明工程市场一片混乱,陷入诸多误区。首先,很多城市都非常重视夜景亮化工程湖北境内有一处神秘古迹,负阴抱阳,规模之大堪称亚洲第二今天的我们不论拥有了怎样的高科技,建立起怎样的摩天大楼,我们依旧是对千百年前的恢宏建筑感到生畏而敬畏。从万里长城到北京故宫从敦煌莫高窟到洛阳龙门石窟,从武当山古建筑群到拉萨布达拉宫湖北首批10个非遗特色村镇街区出炉荆楚文化源远流长,是中华民族文化的重要组成部分。勤劳智慧的湖北人民,创造了多元的文明成果。当古老技艺走进生活,传统与现代碰撞出奇妙的火花当非遗文化走进景区,文化和旅游融合谱写唯美新京城古迹丨妙峰金顶沿着京西古香道,前往中国民俗学的圣地时值夏初,草木葱茏。不同于南方立夏之后暑气渐隆,农人已投入新一年的农忙,北方对夏天的体认此时仍不明显,宛署杂记记载,明时农历四月初,人们习惯赏西湖景,登玉泉山游寺,耍戒坛秋坡及观佛肝功能化验单,关键看哪几点?存起来!教你轻松看懂很多朋友都知道,食欲不振厌恶油腻皮肤发黄眼睛发黄都可能是肝病的征兆。但这些表面症状也可能是其他疾病引起的,不能作为判断肝脏好坏的依据。要了解一个人的肝脏健康状况,验血和腹部b超是比心绞痛一定会痛?医生建议心绞痛可吃这几种食物,或有助于缓解现在的人工作压力大,好不容易有得休息却也是熬到半夜。在这样的环境下,心绞痛变得越来越普遍,为大家的健康埋下了危险的种子。心绞痛听起来总是给人感觉到可能会出现非常明显的疼痛,按照字面睡眠与饮食让你夜不能寐的五大饮食原因睡眠不佳可能有许多原因,包括压力运动光线以及日常活动等等。不过,如果你难以入眠,不妨也从饮食习惯方面找找原因。英国睡眠专家凯文摩根说,虽然没有太多证据证实吃好可以助眠,但吃不好肯定
凤凰商城特惠孤岛惊魂6史低89元坎巴拉29折凤凰商城特惠游戏推荐,坎巴拉太空计划29折孤岛惊魂6史低89元全境封锁2史低44元K社发行商合辑包打包365元。坎巴拉太空计划2现货热销中,游侠送您9折优惠券,券后仅需151。2元CBA三消息山西16分惨败青岛,张宁低迷砍五分,区俊炫六分三帽大家好呀,我是北柠,各位小伙伴们要养成先看后赞的习惯哦!第二阶段常规赛结束之后,山西队排在联盟里的第九位,而青岛队则是排在联盟里的第十四位,两支球队相比的话还是山西队更强一些,并且反转!郑父晒证据,实锤张恒多次不忠,称郑爽深夜发现时彻底崩溃27日,继澄清女儿已经在积极缴纳税务跟孩子处得很好之后,郑父突然晒多张截图,彻底揭穿了张恒的真面目。据他说,张恒在跟郑爽交往期间,多次有不忠行为,而郑爽也是在深夜查岗,没能从男友的中国车用操作系统开源计划发布,首个原创微内核开源版本将于5月正式发布2月18日,中国汽车工业协会软件分会(以下简称软件分会)发布中国车用操作系统开源计划(以下简称开源计划)。普华基础软件一汽东风长安中汽创智中电科32所西部智联地平线芯驰先进操作系统苹果广告收入急剧下降服务业务放缓可能是周期性的苹果公司的整体收入有很大一部分来自其服务业务,其中包括2022财年的781亿美元,2023财年第一季度为208亿美元。许多投资者将苹果的估值归功于这一领域,有人担心,苹果服务业务的消息称微软将在未来几周内推送Win1122H2Moment2更新IT之家2月27日消息,WindowsLatest表示自己拿到了可靠消息,称微软将在未来几周内通过生产渠道推送Windows1122H2Moment2更新。据熟悉内部计划的消息人士消息称英特尔MeteorLake仍有台式机版本,但只有6大核IT之家2月27日消息,英特尔新一代台式机处理器又有新消息传出,称MeteorLake仍有台式机版本,但只有6大核。此前的消息称,英特尔14代酷睿MeteorLake将没有台式机版又搞大逃杀?网传EA战地7小道消息2024发售!最近网上传出一条关于战地7的小道消息,它来自不靠谱国外论坛4chan,不过看起来似乎有点门道。该消息称EA计划在2024或2025年发售战地7,而目前的战地2042将于2023年底早春二月河津樱不依时节乱开花?不,日本的河津樱就是早春二月开花的。当列岛的东北还是搅天风雪,很多地方依然水瘦山寒,伊豆半岛的山野阡陌已是芳菲了。元月半岛南端的下田爪木崎漫山遍野的海边群生水仙祭尚白蒿煮水预防流行感冒作者单方洲题记二月茵陈,三月蒿。五六月份当柴烧。春季气温忽冷忽热,乍暖还寒,同时春季还是还多风的季节。在不经意间,就会偶感风寒。例如室外锻炼出汗,或者因为一个冬季的厚厚的冬衣,让我以油养肤如何操作?我们在上篇文章讲述了以油养肤不同的肤质应该如何选择油类的产品,今天我来讲一下以油养肤具体应该如何操作。第一步蒸脸。可以用热毛巾湿敷23分钟,充分打开毛孔可以让吸收效果更好。第二步按