当前位置:首页 > 嵌入式 > 嵌入式硬件
[导读]这是一个手把手教你学习深度学校的教程。一步一步,我们将要尝试去解决Kaggle challenge中的脸部关键点的检测问题。这份教程介绍了Lasagne,一个比较新的基于Python和Thean

这是一个手把手教你学习深度学校的教程。一步一步,我们将要尝试去解决Kaggle challenge中的脸部关键点的检测问题。

这份教程介绍了Lasagne,一个比较新的基于Python和Theano的神经网络库。我们将用Lasagne去模拟一系列的神经网络结构,讨论一下数据增强(data augmentaTIon)、流失(dropout)、结合动量(momentum)和预先训练(pre-training)。这里有很多方法可以将我们的结果改善不少。

我假设诸位已经知道了一些关于神经网络的只是。所以我们就不介绍神经网络的背景知识了。这里也提供一些好的介绍神经网络的书籍和视频,如Neural Networks and Deep Learning online book。Alec Radford的演讲Deep Learning with Python’s Theano library也是一个快速介绍的好例子。以及ConvNetJS Browser Demos

预先准备

如果你只需要看懂的话,则不需要自己写一个代码然后去执行。这里提供一些安装的教程给那些配置好CUDA的GPU并且想要运行试验的那些人。

我假设你们已经安装了CUDA toolkit, Python 2.7.x, numpy, pandas, matplotlib, 和scikit-learn。安装剩下的依赖包,比如Lasagne和Theano都可以运行下面的指令

pip install -r https://raw.githubusercontent.com/dnouri/kfkd-tutorial/master/requiremen...

注意,为了简洁起见,我没有在命令中创建虚拟环境,但是你需要的。

译者:我是在windows10上面配置这个环境的,安装anaconda(再用此环境安装依赖包)、VS2013(不推荐2015)、CUDA工具即可。

如果一切都顺利的话,你将会在你的虚拟环境下的src/lasagne/examples/目录中找到mnist.py并运行MNIST例子。这是一个对于神经网络的“Hello world”程序。数据中有十个分类,分别是0~9的数字,输入时28&TImes;28的手写数字图片。

cd src/lasagne/examples/

python mnist.py

此命令将在三十秒左右后开始打印输出。 这需要一段时间的原因是,Lasagne使用Theano做重型起重; Theano反过来是一个“优化GPU元编程代码生成面向数组的优化Python数学编译器”,它将生成需要在训练发生前编译的C代码。 幸运的是,我们组需要在第一次运行时支付这个开销的价格。

译者:如果没有配置GPU,用的是CPU的话,应该是不用这么久的编译时间,但是执行时间有一些长。如果用GPU,在第一次跑一些程序的时候,会有提示正在编译的内容。

当训练开始的时候,你会看到

Epoch 1 of 500

training loss: 1.352731

validaTIon loss: 0.466565

validaTIon accuracy: 87.70 %

Epoch 2 of 500

training loss: 0.591704

validation loss: 0.326680

validation accuracy: 90.64 %

Epoch 3 of 500

training loss: 0.464022

validation loss: 0.275699

validation accuracy: 91.98 %

如果你让训练运行足够长,你会注意到,在大约75代之后,它将达到大约98%的测试精度。

如果你用的是GPU,你想要让Theano去使用它,你要在用户的主文件夹下面创建一个.theanorc文件。你需要根据自己安装环境以及自己操作系统的配置使用不同的配置信息:

[global]

floatX = float32

device = gpu0

[lib]

cnmem = 1

译者:这是我的配置文件。

[cuba]

root = C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0

[global]

openmp = False

device = gpu

floatX = float32

allow_input_downcast = True

[nvcc]

fastmath = True

flags = -IC:\Anaconda2\libs

compiler_bindir = C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin

base_compiledir = path_to_a_directory_without_such_characters

[blas]

ldflags =

[gcc]

cxxflags = -IC:\Anaconda2\MinGW

数据

面部关键点检测的训练数据集包括7049(96x96)个灰度图像。 对于每个图像,我们应该学习找到15个关键点的正确位置(x和y坐标),例如

left_eye_center

right_eye_outer_corner

mouth_center_bottom_lip

一个脸部标记出三个关键点的例子。

数据集的一个有趣的变化是,对于一些关键点,我们只有大约2,000个标签,而其他关键点有7,000多个标签可用于训练。

让我们编写一些Python代码,从所提供的CSV文件加载数据。 我们将编写一个可以加载训练和测试数据的函数。 这两个数据集的区别在于测试数据不包含目标值; 这是预测这些问题的目标。 这里是我们的load()函数:

# file kfkd.py

import os

import numpy as np

from pandas.io.parsers import read_csv

from sklearn.utils import shuffle

FTRAIN = '~/data/kaggle-facial-keypoint-detection/training.csv'

FTEST = '~/data/kaggle-facial-keypoint-detection/test.csv'

def load(test=False, cols=None):

"""Loads data from FTEST if *test* is True, otherwise from FTRAIN.

Pass a list of *cols* if you're only interested in a subset of the

target columns.

"""

fname = FTEST if test else FTRAIN

df = read_csv(os.path.expanduser(fname)) # load pandas dataframe

# The Image column has pixel values separated by space; convert

# the values to numpy arrays:

df['Image'] = df['Image'].apply(lambda im: np.fromstring(im, sep=' '))

if cols: # get a subset of columns

df = df[list(cols) + ['Image']]

print(df.count()) # prints the number of values for each column

df = df.dropna() # drop all rows that have missing values in them[!--empirenews.page--]

X = np.vstack(df['Image'].values) / 255. # scale pixel values to [0, 1]

X = X.astype(np.float32)

if not test: # only FTRAIN has any target columns

y = df[df.columns[:-1]].values

y = (y - 48) / 48 # scale target coordinates to [-1, 1]

X, y = shuffle(X, y, random_state=42) # shuffle train data

y = y.astype(np.float32)

else:

y = None

return X, y

X, y = load()

print("X.shape == {}; X.min == {:.3f}; X.max == {:.3f}".format(

X.shape, X.min(), X.max()))

print("y.shape == {}; y.min == {:.3f}; y.max == {:.3f}".format(

y.shape, y.min(), y.max()))

你没有必要看懂这个函数的每一个细节。 但让我们看看上面的脚本输出:

$ python kfkd.py

left_eye_center_x 7034

left_eye_center_y 7034

right_eye_center_x 7032

right_eye_center_y 7032

left_eye_inner_corner_x 2266

left_eye_inner_corner_y 2266

left_eye_outer_corner_x 2263

left_eye_outer_corner_y 2263

right_eye_inner_corner_x 2264

right_eye_inner_corner_y 2264

mouth_right_corner_x 2267

mouth_right_corner_y 2267

mouth_center_top_lip_x 2272

mouth_center_top_lip_y 2272

mouth_center_bottom_lip_x 7014

mouth_center_bottom_lip_y 7014

Image 7044

dtype: int64

X.shape == (2140, 9216); X.min == 0.000; X.max == 1.000

y.shape == (2140, 30); y.min == -0.920; y.max == 0.996

首先,它打印出了CSV文件中所有列的列表以及每个列的可用值的数量。 因此,虽然我们有一个图像的训练数据中的所有行,我们对于mouth_right_corner_x只有个2,267的值等等。

load()返回一个元组(X,y),其中y是目标矩阵。 y的形状是n×m的,其中n是具有所有m个关键点的数据集中的样本数。 删除具有缺失值的所有行是这行代码的功能:

df = df.dropna() # drop all rows that have missing values in them

这个脚本输出的y.shape == (2140, 30)告诉我们,在数据集中只有2140个图像有着所有30个目标值。

一开始,我们将仅训练这2140个样本。 这使得我们比样本具有更多的输入大小(9,216); 过度拟合可能成为一个问题。当然,抛弃70%的训练数据也是一个坏主意。但是目前就这样,我们将在后面谈论。

第一个模型:一个单隐层

现在我们已经完成了加载数据的工作,让我们使用Lasagne并创建一个带有一个隐藏层的神经网络。 我们将从代码开始:

# add to kfkd.py

from lasagne import layers

from lasagne.updates import nesterov_momentum

from nolearn.lasagne import NeuralNet

net1 = NeuralNet(

layers=[ # three layers: one hidden layer

('input', layers.InputLayer),

('hidden', layers.DenseLayer),

('output', layers.DenseLayer),

],

# layer parameters:

input_shape=(None, 9216), # 96x96 input pixels per batch

hidden_num_units=100, # number of units in hidden layer

output_nonlinearity=None, # output layer uses identity function

output_num_units=30, # 30 target values

# optimization method:

update=nesterov_momentum,

update_learning_rate=0.01,

update_momentum=0.9,

regression=True, # flag to indicate we're dealing with regression problem

max_epochs=400, # we want to train this many epochs

verbose=1,

)

X, y = load()

net1.fit(X, y)

我们使用相当多的参数来初始化NeuralNet。让我们看看他们。首先是三层及其参数:

layers=[ # 三层神经网络:一个隐层

('input', layers.InputLayer),

('hidden', layers.DenseLayer),

('output', layers.DenseLayer),

],

# 层的参数:

input_shape=(None, 9216), # 每个批次96x96个输入样例

hidden_num_units=100, # 隐层中的单元数

output_nonlinearity=None, # 输出用的激活函数

output_num_units=30, # 30个目标值

这里我们定义输入层,隐藏层和输出层。在层参数中,我们命名并指定每个层的类型及其顺序。参数input_shape,hidden_??num_units,output_nonlinearity和output_num_units是特定层的参数。它们通过它们的前缀引用层,使得input_shape定义输入层的shape参数,hidden_??num_units定义隐藏层的num_units等等。(看起来有点奇怪,我们必须指定像这样的参数,但结果是它让我们对于受使用scikit-learn的管道和参数搜索功能拥有更好的兼容性。)

我们将input_shape的第一个维度设置为None。这转换为可变批量大小。如果你知道批量大小的话,也可以设置成固定值,如果为None,则是可变值。

我们将output_nonlinearity设置为None。因此,输出单元的激活仅仅是隐藏层中的激活的线性组合。

DenseLayer使用的默认非线性是rectifier,它其实就是返回max(0, x)。它是当今最受欢迎的激活功能选择。通过不明确设置hidden_??nonlinearity,我们选择rectifier作为我们隐藏层的激活函数。

神经网络的权重用具有巧妙选择的间隔的均匀分布来初始化。也就是说,Lasagne使用“Glorot-style”初始化来计算出这个间隔。

还有几个参数。 所有以update开头的参数用来表示更新方程(或最优化方法)的参数。 更新方程将在每个批次后更新我们网络的权重。 我们将使用涅斯捷罗夫动量梯度下降优化方法(nesterov_momentum gradient descent optimization method)来完成这项工作。Lasagne实现的其他方法有很多,如adagrad和rmsprop。我们选择nesterov_momentum,因为它已经证明对于大量的问题很好地工作。[!--empirenews.page--]

”’ optimization method: ””

update=nesterov_momentum,

update_learning_rate=0.01,

update_momentum=0.9,

update_learning_rate定义了梯度下降更新权重的步长。我们稍后讨论学习率和momentum参数,现在的话,这种健全的默认值已经足够了。

上图是不同的最优化方法的对比(animation by?Alec Radford)。星标位置为全局最优值。注意到不添加动量的随机梯度下降是收敛最慢的,我们在教程中从头到尾都是用Nesterov加速过的梯度下降。

在我们的NeuralNet的定义中,我们没有指定一个目标函数来实现最小化。这里使用的还有一个默认值:对于回归问题,它是均方误差(MSE)。

最后一组参数声明我们正在处理一个回归问题(而不是分类),400是我们愿意训练的时期数,并且我们想在训练期间通过设置verbose = 1:

regression=True, # flag to indicate we're dealing with regression problem

max_epochs=400, # we want to train this many epochs

verbose=1,

最后两行加载了数据,然后用数据训练了我们的第一个神经网络。

X, y = load()

net1.fit(X, y)

运行这两行会输出一个表格,每次完成一代就输出一行。每一行里,我们可以看到当前的训练损失和验证损失(最小二乘损失),以及两者的比率。NeuroNet将会自动把输入数据X分成训练集和测试集,用20%的数据作验证。(比率可以通过参数eval_size=0.2调整)

$ python kfkd.py

...

InputLayer (None, 9216) produces 9216 outputs

DenseLayer (None, 100) produces 100 outputs

DenseLayer (None, 30) produces 30 outputs

Epoch | Train loss | Valid loss | Train / Val

--------|--------------|--------------|----------------

1 | 0.105418 | 0.031085 | 3.391261

2 | 0.020353 | 0.019294 | 1.054894

3 | 0.016118 | 0.016918 | 0.952734

4 | 0.014187 | 0.015550 | 0.912363

5 | 0.013329 | 0.014791 | 0.901199

...

200 | 0.003250 | 0.004150 | 0.783282

201 | 0.003242 | 0.004141 | 0.782850

202 | 0.003234 | 0.004133 | 0.782305

203 | 0.003225 | 0.004126 | 0.781746

204 | 0.003217 | 0.004118 | 0.781239

205 | 0.003209 | 0.004110 | 0.780738

...

395 | 0.002259 | 0.003269 | 0.690925

396 | 0.002256 | 0.003264 | 0.691164

397 | 0.002254 | 0.003264 | 0.690485

398 | 0.002249 | 0.003259 | 0.690303

399 | 0.002247 | 0.003260 | 0.689252

400 | 0.002244 | 0.003255 | 0.689606

在相对较快的GPU上训练,我们能够在1分钟之内完成400个epoch的训练。注意测试损失会一直减小。(如果你训练得足够长时间,它将会有很小很小的改进)

现在我们有了一个很好的结果了么?我们看到测试误差是0.0032,和竞赛基准比试一下。记住我们将目标除以了48以将其缩放到-1到1之间,也就是说,要是想计算均方误差和排行榜的结果比较,必须把我们上面得到的0.003255还原到原来的尺度。

>>> import numpy as np

>>> np.sqrt(0.003255) * 48

2.7385251505144153

这个值应该可以代表我们的成绩了。当然,这得假设测试集合的数据和训练集合的数据符合相同的分布,但事实却并非如此。

测试网络

我们刚刚训练的net1对象已经保存了训练时打印在控制台桌面中的记录,我们可以获取这个记录通过train_history_相关属性,让我们画出这两个曲线。

train_loss = np.array([i["train_loss"] for i in net1.train_history_])

valid_loss = np.array([i["valid_loss"] for i in net1.train_history_])

pyplot.plot(train_loss, linewidth=3, label="train")

pyplot.plot(valid_loss, linewidth=3, label="valid")

pyplot.grid()

pyplot.legend()

pyplot.xlabel("epoch")

pyplot.ylabel("loss")

pyplot.ylim(1e-3, 1e-2)

pyplot.yscale("log")

pyplot.show()

我们能够看到我们的网络过拟合了,但是结果还不错。事实上,我们找不到验证错误开始上升的点,所以那种通常用来避免过拟合的early stopping方法在现在还没有什么用处。注意我们没有采用任何正则化手段,除了选择节点比较少的隐层——这可以让过拟合保持在可控范围内。

那么网络的预测结果是什么样的呢?让我们选择一些样例来看一看。

def plot_sample(x, y, axis):

img = x.reshape(96, 96)

axis.imshow(img, cmap='gray')

axis.scatter(y[0::2] * 48 + 48, y[1::2] * 48 + 48, marker='x', s=10)

X, _ = load(test=True)

y_pred = net1.predict(X)

fig = pyplot.figure(figsize=(6, 6))

fig.subplots_adjust(

left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)

for i in range(16):

ax = fig.add_subplot(4, 4, i + 1, xticks=[], yticks=[])

plot_sample(X[i], y_pred[i], ax)

pyplot.show()

第一个模型预测的结果(从测试集抽出了16个样例)

预测结果看起来还不错,但是有点时候还是有一点偏。让我们试着做的更好一些。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭