17、面部表情识别的多层感知器实现

面部表情识别的多层感知器实现

1. 多层感知器(MLP)类的构建

1.1 分类器基类

首先,我们定义一个抽象基类 Classifier ,它包含训练和测试的抽象方法:

from abc import ABCMeta, abstractmethod
class Classifier:
    """Abstract base class for all classifiers"""
    __metaclass__ = ABCMeta
    @abstractmethod
    def fit(self, X_train, y_train):
        pass
    @abstractmethod
    def evaluate(self, X_test, y_test, visualize=False):
        pass

这里, X_train X_test 分别对应训练数据和测试数据,每一行代表一个样本,每一列是该样本的一个特征值。 y_train y_test 分别是训练标签和测试标签向量。

1.2 多层感知器类

接着,我们定义一个新的类 MultiLayerPerceptron ,它继承自 Classifier 基类:

class MultiLayerPerceptron(Classifier):
    def __init__(self, layer_sizes, class_labels, params=None):
        self.num_features = layer_sizes[0]
        self.num_classes = layer_sizes[-1]
        self.class_labels = class_labels
        self.params = params or dict()
        self.model = cv2.ANN_MLP()
        self.model.create(layer_sizes)

构造函数接受 layer_sizes 数组,用于指定网络每层的神经元数量,以及 class_labels 数组,列出所有可用的类别标签。

1.3 标签转换方法

为了方便用户操作, MultiLayerPerceptron 类提供了字符串标签和整数标签之间的转换方法:

def _labels_str_to_num(self, labels):
    """ convert string labels to their corresponding ints """
    return np.array([int(np.where(self.class_labels == l)[0])  
        for l in labels])

def _labels_num_to_str(self, labels):
    """Convert integer labels to their corresponding string  
        names """
    return self.class_labels[labels]

1.4 加载和保存方法

提供简单的包装器,用于加载和保存预训练的 MLP:

def load(self, file):
    """ load a pre-trained MLP from file """
    self.model.load(file)

def save(self, file):
    """ save a trained MLP to file """
    self.model.save(file)

2. MLP 的训练

2.1 训练方法

根据 Classifier 基类的要求,我们在 fit 方法中进行训练:

def fit(self, X_train, y_train, params=None):
    """ fit model to data """
    if params is None:
        params = self.params
    y_train = self._labels_str_to_num(y_train)
    y_train = self._one_hot(y_train).reshape(-1,  
        self.num_classes)
    self.model.train(X_train, y_train, None, params=params)

其中, params 是一个可选的字典,包含训练相关的选项,如终止条件和学习算法。例如,使用反向传播并在 300 次迭代或损失小于 0.01 时终止训练:

params = dict(
    term_crit = (cv2.TERM_CRITERIA_COUNT, 300, 0.01),  
    train_method = cv2.ANN_MLP_TRAIN_PARAMS_BACKPROP)

2.2 独热编码方法

由于 cv2.ANN_MLP 模块的 train 方法不允许整数值的类别标签,我们需要将 y_train 转换为独热编码:

def _one_hot(self, y_train):
    """Convert a list of labels into one-hot code """
    num_samples = len(y_train)
    new_responses = np.zeros(num_samples * self.num_classes,  
        np.float32)
    resp_idx = np.int32(y_train + 
        np.arange(num_samples) * self.num_classes)
    new_responses[resp_idx] = 1
    return new_responses

3. MLP 的测试

3.1 评估方法

根据 Classifier 基类的要求,我们在 evaluate 方法中评估模型性能:

def evaluate(self, X_test, y_test, visualize=False):
    """ evaluate model performance """
    ret, Y_vote = self.model.predict(X_test)
    y_test = self._labels_str_to_num(y_test)
    accuracy = self._accuracy(y_test, Y_vote)
    precision = self._precision(y_test, Y_vote)
    recall = self._recall(y_test, Y_vote)
    return (accuracy, precision, recall)

这里,我们根据输出层神经元的活动来构建投票矩阵,然后计算准确率、精确率和召回率。

3.2 预测方法

还提供了 predict 方法,用于预测单个数据样本的标签:

def predict(self, X_test):
    """ predict the labels of test data """
    ret, Y_vote = self.model.predict(X_test)
    # find the most active cell in the output layer
    y_hat = np.argmax(Y_vote, 1)
    # return string labels
    return self._labels_num_to_str(y_hat)

4. 运行脚本

4.1 数据加载和预处理

使用 train_test_mlp.py 脚本训练和测试 MLP。脚本首先解析自制数据集并提取所有类别标签:

import cv2
import numpy as np
from datasets import homebrew
from classifiers import MultiLayerPerceptron
def main():
    # load training data
    (X_train, y_train),(X_test, y_test) =
        homebrew.load_data("datasets/faces_training.pkl",  
        num_components=50, test_split=0.2,  
        save_to_file="datasets/faces_preprocessed.pkl",  
        seed=42)
    if len(X_train) == 0 or len(X_test) == 0:
        print "Empty data"
    raise SystemExit
    # convert to numpy
    X_train = np.squeeze(np.array(X_train)).astype(np.float32)
    y_train = np.array(y_train)
    X_test = np.squeeze(np.array(X_test)).astype(np.float32)
    y_test = np.array(y_test)
    # find all class labels
    labels = np.unique(np.hstack((y_train, y_test)))

4.2 超参数调整

通常,神经网络的最佳大小事先未知,需要调整超参数。我们在循环中运行不同大小的 MLP,并将最佳结果保存到文件中:

params = dict( term_crit = (cv2.TERM_CRITERIA_COUNT, 300,  
    0.01), train_method=cv2.ANN_MLP_TRAIN_PARAMS_BACKPROP,  
    bp_dw_scale=0.001, bp_moment_scale=0.9 )
save_file = 'params/mlp.xml'
num_features = len(X_train[0])
num_classes = len(labels)
# find best MLP configuration
print "1-hidden layer networks"
best_acc = 0.0 # keep track of best accuracy
for l1 in xrange(10):
    # gradually increase the hidden-layer size
    layer_sizes = np.int32([num_features, 
        (l1 + 1) * num_features / 5, 
        num_classes])
    MLP = MultiLayerPerceptron(layer_sizes, labels)
    print layer_sizes
    MLP.fit(X_train, y_train, params=params)
    (acc, _, _) = MLP.evaluate(X_train, y_train)
    print " - train acc = ", acc
    (acc, _, _) = MLP.evaluate(X_test, y_test)
    print " - test acc = ", acc
    if acc > best_acc:
        # save best MLP configuration to file
        MLP.save(save_file)
    best_acc = acc

4.3 流程图

graph LR
    A[加载数据] --> B[数据预处理]
    B --> C[超参数调整]
    C --> D[训练MLP]
    D --> E[评估MLP]
    E --> F{是否最佳?}
    F -- 是 --> G[保存模型]
    F -- 否 --> C

4.4 表格:评估指标

指标 含义
准确率 模型正确预测的样本数占总样本数的比例
精确率 模型预测为正类的样本中,实际为正类的比例
召回率 实际为正类的样本中,被模型正确预测为正类的比例

5. 应用到实时分类

5.1 主 GUI 应用

保存的 params/mlp.xml 文件包含网络配置和学习到的权重,可以通过将 loadMLP='params/mlp.xml' 传递给 FaceLayout 类的 init_algorithm 方法加载到主 GUI 应用中。在主函数例程( chapter7.py )中,会加载预训练的级联分类器和多层感知器,并将它们应用到网络摄像头的实时流的每一帧上。

5.2 测试模式

在应用中选择“Test”单选按钮,会触发 EVT_RADIOBUTTON 事件,绑定到 FaceLayout._on_testing ,禁用所有与训练相关的按钮,将应用切换到测试模式。在测试模式下,预训练的 MLP 分类器会应用到实时流的每一帧,尝试预测当前的面部表情。

5.3 处理帧方法

FaceLayout._process_frame 方法用于检测面部并在测试模式下预测面部标签:

def _process_frame(self, frame):
    """ detects face, predicts face label in testing mode """
    success, frame, self.head = self.faces.detect(frame)
    if success and self.testing.GetValue():
        success, head = self.faces.align_head(self.head)
        if success:
            X, _, _ = homebrew.extract_features( 
                [head.flatten()], self.pca_V, self.pca_m)
            label = self.MLP.predict(np.array(X))[0]
            cv2.putText(frame, str(label), (x,y-20),  
                cv2.FONT_HERSHEY_COMPLEX, 1, (0,255,0), 2)
    return frame

该方法的具体步骤如下:
1. 检测当前帧的降采样灰度版本中的面部。
2. 如果检测到面部且处于测试模式,对齐头部区域。
3. 使用预加载的主成分分析(PCA)基向量和均值对当前帧进行相同的预处理。
4. 提取特征并使用预训练的 MLP 预测当前帧的类别标签。
5. 在当前帧的边界框上方显示预测的标签。

5.4 流程图

graph LR
    A[开始] --> B[检测面部]
    B -- 成功 --> C{是否测试模式?}
    C -- 是 --> D[对齐头部区域]
    D -- 成功 --> E[提取特征]
    E --> F[预测标签]
    F --> G[显示标签]
    G --> H[结束]
    C -- 否 --> H
    B -- 失败 --> H
    D -- 失败 --> H

6. 结果与总结

6.1 结果

尽管分类器仅在大约 100 个训练样本上进行了训练,但它能够在实时流的每一帧中可靠地检测各种面部表情,无论当时面部看起来多么扭曲。这表明学习到的神经网络既没有欠拟合也没有过拟合数据,因为它能够为新的数据样本预测正确的类别标签。

6.2 总结

通过构建多层感知器(MLP)分类器并将其应用于面部表情识别,我们结合了目标检测和目标识别的多种技能,实现了一个端到端的应用。具体过程包括:
1. 定义分类器基类和多层感知器类。
2. 实现 MLP 的训练和测试方法。
3. 运行脚本进行数据加载、预处理和超参数调整。
4. 将预训练的 MLP 应用到实时分类中。

6.3 拓展与展望

在机器学习领域,还有许多其他的库和算法可供探索,例如 pylearn scikit - learn pycaffe 等。深度学习爱好者可以研究 Theano Torch 。如果在应用算法时缺乏数据集,可以访问 UC Irvine 机器学习库。

6.4 表格:相关库与资源

资源 描述 链接
pylearn 机器学习库 https://github.com/lisa - lab/pylearn2
scikit - learn 机器学习库 http://scikit - learn.org
pycaffe 深度学习库 http://caffe.berkeleyvision.org
Theano 深度学习库 http://deeplearning.net/software/theano
Torch 深度学习库 http://torch.ch
UC Irvine 机器学习库 数据集资源 http://archive.ics.uci.edu/ml

通过不断学习和实践,我们可以进一步改进和拓展这个面部表情识别应用,使其在更多场景中发挥作用。

基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样与统计,通过模拟系统元件的故障与修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构与设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码与案例分析,便于复现和扩展应用。; 适合人群:具备电力系统基础知识和Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行与可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理与实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估与优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值