分享IT技术,分享生活感悟,热爱摄影,热爱航天。
神经网络可以类似最小二乘法一样作为一种基于经验的数据拟合方法,相比最小二乘法神经网络在拟合数据时不需要对输出输出之间的函数关系有提前的认识,而是通过引入大量的参数试图通过对参数的优化得到最佳的拟合结果。而实际中可通过对时间序列的拟合,实现对时间序列的未来趋势进行预测,如气温、客流、股价等。而循环神经网络(RNN)作为一种针对时间序列的方法,充分利用时间序列中前后数据的关联性,实现更高的拟合效果。
这里以股价的预测为例,使用Tensorflow中的keras实现循环神经网络的建模、训练实现对上证综合指数的预测。
为实现训练,首先需要获得用于训练的数据集,这里通过Tushare获得上证综合指数的历史数据,其还提供了其他各种财经数据,专业版需要注册获得接口TOKEN使用,普通版本可以直接获取数据不需要注册,目前暂时还可以使用。其返回的数据为pandas封装,需要安装Python的pandas模块,可以使用pip直接安装,同时安装Tensorflow,如果使用的CUDA为10.1版本,对应的cuDNN需要选择7.4.x,Tensorflow则可选择安装2.3.0版本。
pip install pandas pip install tensorflow==2.3.0
Tushare的使用非常简单,直接调用获取数据的方法即可返回数据集,需要传入的参数包括股票的代码,上证综合指数为sh000001,以及获取数据的日期区间。同时将数据按照时间索引进行排序,获取数据的代码如下
data = tushare.get_hist_data('sh000001', '2011-01-01', '2020-12-31'); data.index = data.index.astype('datetime64[ns]'); data = data.sort_index()['close'].values.reshape(-1, 1);
2. 生成训练数据集
训练数据集一般包括两个数组x_train和y_train,其中x_train数组中的一个元素为一个数据输入,y_train数组中的一个元素为一个数据输出,输入和输出数据都可以含有多个数据。例如在使用循环神经网络时输入的数据就是预测时刻之前的n个时刻的数据,同时在生成训练集前,对数据进行归一化处理
#归一化处理 scl = MinMaxScaler(); data = scl.fit_transform(data); #预测使用的数据点个数及预测的数据点个数 look_back = 30; forward_days = 1; #生成训练数据集 x_train, y_train = [], []; for i in range(0, len(data) - look_back - forward_days + 1): x_train.append(data[i : (i + look_back)]); y_train.append(data[(i + look_back) : (i + look_back + forward_days)]); x_train = numpy.array(x_train); y_train = numpy.array(y_train);
数据准备完成后便是构造循环神经网络模型,这里使用tensorflow中提供的keras来定义一个循环神经网络,包括两个长短期记忆层和1个全连接层,其代码如下
#初始化循环神经网络模型 model = Sequential(); #第一层长短期记忆层 model.add(LSTM(100, input_shape=(look_back, 1), return_sequences=True)); #防止过拟合增加Dropout层 model.add(Dropout(0.2)); #第二层长短期记忆层 model.add(LSTM(80)); #最后的全连接层 model.add(Dense(forward_days, activation='tanh')); #编译模型 model.compile(loss='mean_squared_error', optimizer='adam'); #进行数据拟合 model.fit(x_train, y_train, epochs=100, batch_size=16); #保存训练得到的模型 model.save(model_file);
在使用Ryzen 3600+RTX2080Super的环境下,仅使用CPU训练大约耗时52s,使用CUDA加速后则只需要18s。为了对比运行速度,在训练过程中可通过配置以下环境变量实现禁用CUDA加速。
import os; os.environ['CUDA_VISIBLE_DEVICES'] = '-1';
在完成训练得到模型后,就可以使用模型对未来的数据进行预测了,预测时需要构造与训练时格式相同的x_test数组,通过模型可以得到对应的y_test预测结果,其代码如下
#获取预测需要的数据,并对数据进行处理 data = tushare.get_hist_data(no, '2021-01-01'); data.index = data.index.astype('datetime64[ns]'); data = data.sort_index()['close'].values.reshape(-1, 1); data = scl.fit_transform(data); #构造预测的输入数据集 x_test = []; for i in range(0, len(data) - look_back - forward_days + 1): x_test.append(data[i : (i + look_back)]); x_test = numpy.array(x_test); #使用模型对结果进行预测 y_test = model.predict(x_test);
同时使用matplotlib还可以绘制预测的结果和实际的结果的对比曲线
import matplotlib.pyplot as plt; plt.plot(scl.inverse_transform(y_test.reshape(-1, 1))[0:-1]); plt.plot(scl.inverse_transform(data[look_back + 1:])); plt.show();
红线是实际的曲线,蓝线是预测的曲线,总体上匹配度还可以。
基于特征以及使用深度学习进行人脸识别已经是非常成熟的算法,应用广泛的计算机视觉库opencv中就提供了人脸识别的相关算法,能够很好的识别图片或视频中的人脸部分。而实际应用中除了要识别出人脸,还需要对人脸的特征进行比对,如进行身份认证或比对是否为同一人等。如果直接使用计算图片相似度的方法,不仅运行速度较慢,同时由于包含人脸的矩形区域内还会夹杂一些干扰信息,对比的精度也会收到影响。
这里使用基于深度学习库dlib的人脸识别工具face_recognition,首先识别图片中的人脸,同时提取人脸的特征向量,对比时可以直接对提取到的不同人脸的特征向量进行对比,这里使用经典的余弦相似度算法,即计算两个特征向量夹角的余弦值,其值越接近1则相似度越高。
face_recognition为python编写,可以直接使用python的pip包管理工具进行安装,其主要依赖cblas(要用cblas而不是openblas)、numpy、matplotlib、dlib,安装过程中会自动编译dlib,过程中需要至少4GB以上的可用内存。
pip install face_recognition
使用load_image_file方法可以读入图片文件,该方法返回一个图片的多维数组和opencv中的格式一致。face_locations方法传入一个图片多维数组,可以返回其中的人脸所在的举行区域,其中矩形区域的顺序为上、右、下、左。使用face_encodings方法传入一个图片的多维数组,可以返回一个128维的人脸特征向量。
import face_recognition; if __name__ == '__main__': im = face_recognition.load_image_file('test.jpg'); boxes = face_recognition.face_locations(im); encodings = face_recognition.face_encodings(im);
另外face_distance和compare_faces可以计算多个已知的人脸特征和一个未知的人脸特征的相似度和对比结果,默认的阈值会取0.6。其中compare_faces本质就是在调用face_distance。
im1 = face_recognition.load_image_file('1/l.jpg'); enc1 = face_recognition.face_encodings(im1)[0]; im2 = face_recognition.load_image_file('2/1.jpg'); enc2 = face_recognition.face_encodings(im2)[0]; #注意这里第一个参数是多个已知人脸的特征向量 face_recognition.face_distance([enc1], enc2); face_recognition.compare_faces([enc1], enc2)
3. 进行人脸的匹配
不清楚为什么该工具默认会使用欧式距离的方法来计算相似度,实际测试下来使用欧式距离计算的相似度波动较大,整体的阈值选择较为困难。
2个目录中各有6张图片,其中目录1中的图片,分别为蔡徐坤、李宇春、刘翔、马云、姚明、王怀南。目录2中依次为蔡徐坤、马云、王怀南、姚明、李宇春、刘翔。如使用命令行工具进行两个目录之间图片的对比
face_recognition 1 2 --show-distance=1 #输出结果 2/1.jpg,cxk,0.33241630184812043 2/1.jpg,lyc,0.5966439550889049 2/6.jpg,lx,0.4915904587201082 2/4.jpg,lx,0.5309307486036086 2/4.jpg,my,0.5750886946477217 2/4.jpg,ym,0.38126356882352785 2/2.jpg,my,0.34452493549783725 2/3.jpg,lx,0.5901235869708715 2/3.jpg,whn,0.3484571564371876 2/3.jpg,my,0.5870175925341533 2/5.jpg,lyc,0.3480285326046423
一些图片识别出了多组结果,如果选择距离最小的一个,则可以全部识别正确。但图6的距离有0.49,这种情况有可能该人脸仅仅是和刘翔的相似度最高,而其实并不是其中的任何一个人。
如果使用余弦相似度,则只用face_recognition计算得到人脸的特征向量,然后自行计算相似度,其的代码如下
import face_recognition; import numpy; from numpy import linalg; import os; if __name__ == '__main__': dir1 = '1/'; files1 = os.listdir(dir1); size = len(files1); N = 128; #已知人脸特征向量矩阵 A = numpy.zeros((size, N)); i = 0; for f in files1: im = face_recognition.load_image_file(dir1 + f); enc = face_recognition.face_encodings(im)[0]; #特征向量长度归一化 enc /= linalg.norm(enc); A[i] = enc; i += 1; dir2 = '2/'; files2 = os.listdir(dir2); for f in files2: im = face_recognition.load_image_file(dir2 + f); enc = face_recognition.face_encodings(im)[0]; enc /= linalg.norm(enc); #计算相似度 r = A @ enc; #取相似度最高的一个 idx = numpy.argmax(r); print("%s %s %f" % (f, files1[idx], r[idx]));
使用同样的例子运行结果如下
1.jpg cxk.jpg 0.974498 6.jpg lx.jpg 0.935104 4.jpg ym.jpg 0.959824 2.jpg my.jpg 0.968253 3.jpg whn.jpg 0.967666 5.jpg lyc.jpg 0.969720
同样完全计算正确,同时相似度都达到了较高的0.9以上,相比距离更容易设定阈值。
在实际使用中已知的人脸特征向量矩阵A可以提前算好并保存,同时也方便进行增量计算,实际一次匹配的过程仅需要进行一次矩阵和向量的乘法即可完成,计算的效率相对还是比较高的。