深入浅出PyTorch:从模型到源码
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.4 输入数据的表示方式

前面已经讲到了可以用张量(包括向量和矩阵)的形式来表示神经网络中的数据。一般来说,在神经网络的神经元之间互相进行传递的数据是以浮点数的形式来表示的。与之相反,日常生活中接触到的图像、文本和语音都不是按照浮点数的形式进行存储的。为了能够利用这些数据进行深度学习,我们需要把这些内容转换为浮点数的形式,才能输入神经网络进行计算,这个过程称之为数据的预处理(Preprocessing)。下面简单介绍一下常见的几类数据如何进行预处理。

1.4.1 图像数据的表示方式

在前面已经简单介绍过,图像数据可以表示为像素点的集合,而每个像素点有一个(灰度,Grayscale)、三个(RGB)或者四个(RGBA)通道,单个像素点的通道的取值范围决定了像素可以表示的对比度的大小,一般在最亮和最暗的值之间离散地取256个分立的值,即取0~255之间的整数,分别代表不同的对比度。于是,一张图片可以表示为h×w×c的三维张量,其中h是图片的高度(像素数),w是图片的宽度(像素数),c是图片的通道数目(如果是灰度图片,则c=1;若是红绿蓝,则c=3;若是红绿蓝以及透明度,则c=4)。由于0~255之间的整数在计算机上可以用一字节来表示,所以一个像素的一个通道大小是一字节(8比特),一般称之为byte或者uint8类型。当然,由于神经网络的运算主要是通过浮点数来进行的,因此,需要进一步把图片转换为浮点数类型的张量。另外,因为图片的大小(高度和宽度)各不相同,而神经网络在训练过程中一般会同时批量处理很多图片,所以需要把图片调整为相同大小,可以通过最近邻插值(Nearest Neighbor Interpolation)算法,或双线性插值(Bilinear Interpolation)等算法来把图片设置为目标的大小(这里假设为h×w大小,其中h为调整大小后图片的高度,w为调整大小后图片的宽度)。调整好大小之后,就可以把图片所有像素的所有通道除以255,转换为0~1之间的浮点数。这样,假设有n张图片,经过一系列变换之后,我们可以把图片转换为n×h×w×c的一个张量(其中c为图片的通道,如前所述,一般c=3或c=4)。需要注意的是,为了能够增加图片的多样性,人们一般在调整图片大小之前会对图片做一些特殊处理,比如,从图片中随机裁剪出一定的区域(Random Cropping),用这部分图片来调整图片大小,进而转换为浮点数张量,或者对图片进行色彩的轻微变化(Jittering,主要过程是把图片从RGB先变换到HSV,即色相(Hue)、饱和度(Saturation)和明度(Brightness Value),然后在这三个值上做5%~10%的随机增减,再变换回RGB),最后进行缩放并转换成张量。做这些处理的目的是扩增数据集,增加神经网络的泛化能力。另外,在转换为张量之后,可能还需要其他一些操作才能输入神经网络。首先就是归一化(Normalization)。由于图像像素值的分布多种多样,为了能够让数据的分布规整,从而有利于神经网络的训练,我们需要让一批图像的张量减去所有图像的平均值,除以所有图像的方差,这个过程称之为归一化,具体可以参考式(1.23)~式(1.25),其中,μ是所有图像像素的平均,σ是所有图像像素的标准差,a′是归一化后的图像。归一化数据输入能够有效增加神经网络训练的数值稳定性,更有利于优化损失函数,从而提高训练结果的准确率。

1.4.2 文本数据的表示方式

除图像以外,深度学习的另一种重要的输入是文本。相对于图像可以数值化,文本是由离散的字符组成的,我们在转换文本为数值张量的过程中需要进行一系列的预处理。首先需要对文本做的处理是分词(Tokenization)。顾名思义,分词就是把连续的文本转换为单词的序列。对英文等基于单词的文本来说,这个过程相对比较简单,就是根据空格和标点符号把连续的英文句子或段落转换为单词的列表。对中文来说,我们需要使用一些分词工具把一段或者一句中文分成中文词组的列表。常用的中文分词工具有THULAC和Jieba等。有了分词之后,接下来需要做的一件事情是去停词。停词(Stop words)指的是文本中出现频率相对比较高,但是对于文本实际意义没有太大关联的单词。在很多自然语言处理任务中,这些词可以被忽略而不影响文本的意思,代表性的一些单词在英文中有“the”“of”等,在中文中有“啊”“哦”等。去停词之后可能要对文本做正则化(Normalization)处理。一些意思相同的单词在文本中的意义可能相同,但是却有不同的文本表现形式,比如,中文数字和阿拉伯数字,这时就需要把不同的文本形式转换为一致的文本形式,方便下一步处理,这个过程就称为正则化。经过前面的预处理之后,我们可以把预处理的结果直接转换为词向量,这个过程称为词嵌入(Embedding)。具体的构造过程是:首先建立一个词表,其中每个单词对应一定大小的词向量,假如有n个单词,每个单词对应一个长度为m的向量,那么这个词嵌入矩阵就可以构成一个n×m的矩阵(如图1.9所示,每个单词是一个向量,这个向量的大小为m)。对于深度学习来说,这个矩阵的元素首先可以进行随机初始化(一般初始化为正态分布或者均匀分布),也可以使用预训练的词向量(如Word2vec或者GloVe算法预先训练好的词向量)进行初始化。另外需要提到的一点是,我们在自然语言处理过程中经常会使用一些特殊的字符,比如文本的开头(标志着文本开始)、文本的结尾(标志着文本的结束)、占位词(为了让一组文本的单词数目相同,需要对较短的文本增加占位词,让所有的文本长度对齐),以及未知单词(代表任何一个不在词表内的单词)。还有一个问题是如何挑选向量长度为m的大小。这里有个经验性的规律,即m的大小和n的四次方根成正比,比例系数在1~10之间。另外,为了词嵌入矩阵在内存中对齐,建议m选择为2的整数次方。举例来说,我们有10000个单词组成的词表,由于10000的四次方根是10,我们可以选择32和64作为m的大小。当然这个规律不是绝对的,大家在实践中可以尝试使用不同的m,并测试不同m下模型的表现,从而选出最好的m的大小。

图1.9 词嵌入示意图

1.4.3 音频数据的表示方式

音频也是一个比较重要的数据输入。下面以最简单的16bit的脉冲编码调制(Pulse-code Modulation,PCM)的音频信号为例,介绍如何从音频信号中提取特征。首先,这里的16bit代表这个音频将会按照信号的振幅取离散的216个值,即-32768~+32767,振幅越大,声音的强度越大。音频信号的另一个重要参数是采样率,比如采样率为44.1 kHz,意思就是每秒采样441000个点。如果需要提取音频信号中的信息,就需要对采样时间×采样率数目的点做预处理。首先需要把振幅从整数转变为-1~+1之间的浮点数,即对所有的振幅先加32768,除以32768,然后减去1.0。我们可以画出振幅随着时间的变化,如图1.10所示。有了振幅之后,第一步需要做的事情是预加重,即对音频做式(1.26)所示的变换,其中α是参数,一般取值为0.95~0.97(这里假设有N个点,序号从0到N-1,其中第0个点不发生改变)。在数学上,预加重相当于一个高通滤波器,起到了提高高频信号分量、滤除低频噪声的作用。在实际应用中,预加重是一个可选的预处理步骤,对于信号中噪声的滤除有一定的效果。

图1.10 一段50 s的音频示意图(采样率为44.1kHz)

在前面得到的信号的基础上,我们需要对信号进行分帧(Framing)和加窗(Window)处理。分帧即把音频切成一小段,一般每段长度在20ms到40ms之间,两个段之间重叠在50%左右,比如,选择25ms作为音频段落大小,两个段落之间的重叠为15ms(后一段开头距离前一段开头为10ms)。一般来说,我们会让采样点的数目接近2的整数次幂,比如,对于采样率为44.1kHz的音频,为了计算方便,我们可选取1024个点(大约23ms),前后音频段落开头间隔512个点(大约11ms)。分帧之后,需要把每一帧的信号乘以窗口函数,其目的是为了防止信号泄漏,增加后续傅里叶变换以后频率空间信号的信噪比。有关具体的窗口函数的形式,读者可以参考相关资料。其基本方法是根据音频片段的大小(比如1024)计算出每一点窗函数的值,然后把窗函数的值和信号的值做逐点乘积,最后输出结果。

有了加窗的信号,接下来需要做的是对信号进行快速傅里叶变换(Fast Fourier Transform,FFT)。在做完快速傅里叶变换之后(结果是一个复数的向量,长度和原始信号长度相同),我们可以得到信号在频率上的分布。可以画出快速傅里叶变换后的信号功率(复数的模长平方)相对频率的分布,如图1.11所示。有了傅里叶变换谱之后,需要得到梅尔尺度(Mel-scale)上的特征信息,即对数频率尺度的特征。由于梅尔尺度的特征信息是通过一组过滤器实现的,这里称之为梅尔过滤器(Mel Filter Banks)。其中,梅尔尺度m和频率尺度f的变换公式如式(1.27)和式(1.28)所示。根据奈奎斯特采样定理(Nyquist Sampling Theorem),能够最大表示信号的频率是系统采样率的一半(超过这个频率会产生信号的混叠),可以通过式(1.27)计算出最大的梅尔尺度值,然后在0和这个最大值之间均匀采样一定的点数(比如40个点),再通过式(1.28)做逆变换计算出40个点对应的频率。在相邻的频率之间做0~1之间的线性插值,可以得到对应频率的系数。把傅里叶变换的结果乘以梅尔过滤器对应的系数,即可提取出对应的特征。我们可以进一步画出梅尔过滤器提取出的特征,如图1.12所示。由于梅尔过滤器的系数之间有一定相关性,为了减少线性相关,我们可以进一步使用梅尔倒频谱系数(Mel-Frequency Cepstral Coefficients,MFCC)来代表音频片段的特征,具体计算方法是对功率谱取对数,做一次离散余弦变换(Discrete Cosine Transform,DCT),取低频的前几个分量系数(一般可以取除直流分量外的前12个系数),这里不再赘述,读者有兴趣可以参考相关的资料。最后为了增加信噪比,需要做的一个处理是把信号减去信号对于时间的平均,这个过程称之为平均归一化(Mean Normalization),这样可以有效提高机器学习和深度学习模型的识别效果。

图1.11 一帧音频(1024个点)、加窗后的结果、快速傅里叶变换后的结果

图1.12 梅尔过滤器提取出特征随时间的变化图