keras实现swin_transformer

import os
import cv2
import dlib
import numpy as np
import math
import keras
from keras.models import Sequential, Model
from keras.layers import Dense, Dropout, Input, Embedding, Flatten, GlobalAveragePooling1D
from keras.utils import np_utils
from sklearn.model_selection import train_test_split
from keras.layers import Layer
from keras import backend as K

# 自定义位置编码层
class Position_Embedding(Layer):
    def __init__(self, size=None, mode='sum', **kwargs):
        self.size = size  # 位置编码的维度
        self.mode = mode  # 'sum' 或 'concat' 模式
        super(Position_Embedding, self).__init__(**kwargs)

    def call(self, x):
        # 如果未指定size或模式为'sum',从输入推断size
        if (self.size is None) or (self.mode == 'sum'):
            self.size = int(x.shape[-1])
        batch_size, seq_len = K.shape(x)[0], K.shape(x)[1]
        position_j = 1. / K.pow(10000., 2 * K.arange(self.size / 2, dtype='float32') / self.size)
        position_j = K.expand_dims(position_j, 0)
        position_i = K.cumsum(K.ones_like(x[:, :, 0]), 1) - 1  # 生成位置索引
        position_i = K.expand_dims(position_i, 2)
        position_ij = K.dot(position_i, position_j)
        position_ij = K.concatenate([K.cos(position_ij), K.sin(position_ij)], 2)
        if self.mode == 'sum':
            return position_ij + x
        elif self.mode == 'concat':
            return K.concatenate([position_ij, x], 2)

    def compute_output_shape(self, input_shape):
        if self.mode == 'sum':
            return input_shape
        elif self.mode == 'concat':
            return (input_shape[0], input_shape[1], input_shape[2] + self.size)


# 自定义多头自注意力层
class Attention(Layer):
    def __init__(self, nb_head, size_per_head, **kwargs):
        self.nb_head = nb_head  # 注意力头数
        self.size_per_head = size_per_head  # 每个头的维度
        self.output_dim = nb_head * size_per_head  # 输出维度
        super(Attention, self).__init__(**kwargs)

    def build(self, input_shape):
        # 初始化Q、K、V转换的权重
        self.WQ = self.add_weight(name='WQ', shape=(input_shape[0][-1], self.output_dim),
                                  initializer='glorot_uniform', trainable=True)
        self.WK = self.add_weight(name='WK', shape=(input_shape[1][-1], self.output_dim),
                                  initializer='glorot_uniform', trainable=True)
        self.WV = self.add_weight(name='WV', shape=(input_shape[2][-1], self.output_dim),
                                  initializer='glorot_uniform', trainable=True)
        super(Attention, self).build(input_shape)

    def Mask(self, inputs, seq_len, mode='mul'):
        if seq_len is None:
            return inputs
        else:
            mask = K.one_hot(seq_len[:, 0], K.shape(inputs)[1])
            mask = 1 - K.cumsum(mask, 1)
            for _ in range(len(inputs.shape) - 2):
                mask = K.expand_dims(mask, 2)
            if mode == 'mul':
                return inputs * mask
            if mode == 'add':
                return inputs - (1 - mask) * 1e12

    def call(self, x):
        if len(x) == 3:
            Q_seq, K_seq, V_seq = x
            Q_len, V_len = None, None
        elif len(x) == 5:
            Q_seq, K_seq, V_seq, Q_len, V_len = x

        Q_seq = K.dot(Q_seq, self.WQ)
        Q_seq = K.reshape(Q_seq, (-1, K.shape(Q_seq)[1], self.nb_head, self.size_per_head))
        Q_seq = K.permute_dimensions(Q_seq, (0, 2, 1, 3))
        K_seq = K.dot(K_seq, self.WK)
        K_seq = K.reshape(K_seq, (-1, K.shape(K_seq)[1], self.nb_head, self.size_per_head))
        K_seq = K.permute_dimensions(K_seq, (0, 2, 1, 3))
        V_seq = K.dot(V_seq, self.WV)
        V_seq = K.reshape(V_seq, (-1, K.shape(V_seq)[1], self.nb_head, self.size_per_head))
        V_seq = K.permute_dimensions(V_seq, (0, 2, 1, 3))

        A = K.batch_dot(Q_seq, K_seq, axes=[3, 3]) / self.size_per_head**0.5
        A = K.permute_dimensions(A, (0, 3, 2, 1))
        A = self.Mask(A, V_len, 'add')
        A = K.permute_dimensions(A, (0, 3, 2, 1))
        A = K.softmax(A)

        O_seq = K.batch_dot(A, V_seq, axes=[3, 2])
        O_seq = K.permute_dimensions(O_seq, (0, 2, 1, 3))
        O_seq = K.reshape(O_seq, (-1, K.shape(O_seq)[1], self.output_dim))
        O_seq = self.Mask(O_seq, Q_len, 'mul')
        return O_seq

    def compute_output_shape(self, input_shape):
        return (input_shape[0][0], input_shape[0][1], self.output_dim)


# 自定义回调函数,用于跟踪训练过程中的损失和准确率
class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.losses = {'batch': [], 'epoch': []}
        self.accuracy = {'batch': [], 'epoch': []}
        self.val_loss = {'batch': [], 'epoch': []}
        self.val_acc = {'batch': [], 'epoch': []}

    def on_batch_end(self, batch, logs={}):
        self.losses['batch'].append(logs.get('loss'))
        self.accuracy['batch'].append(logs.get('accuracy'))
        self.val_loss['batch'].append(logs.get('val_loss'))
        self.val_acc['batch'].append(logs.get('val_accuracy'))

    def on_epoch_end(self, batch, logs={}):
        self.losses['epoch'].append(logs.get('loss'))
        self.accuracy['epoch'].append(logs.get('accuracy'))
        self.val_loss['epoch'].append(logs.get('val_loss'))
        self.val_acc['epoch'].append(logs.get('val_accuracy'))

    def loss_plot(self, loss_type):
        iters = range(len(self.losses[loss_type]))
        plt.figure()
        plt.plot(iters, self.accuracy[loss_type], 'r', label='训练准确率')
        plt.plot(iters, self.losses[loss_type], 'g', label='训练损失')
        if loss_type == 'epoch':
            plt.plot(iters, self.val_acc[loss_type], 'b', label='验证准确率')
            plt.plot(iters, self.val_loss[loss_type], 'k', label='验证损失')
        plt.grid(True)
        plt.xlabel(loss_type)
        plt.ylabel('准确率-损失')
        plt.legend(loc="upper right")
        plt.show()


# 使用dlib检测人脸和获取关键点的代码略

# 加载数据和预处理
t = 0
k = 0
x2 = []
y2 = []
time = 1
path_traindata = "MMEW_Final/Micro_Expression"
path1 = os.listdir(path_traindata)
for subject in path1:
    if subject == 'others':
        continue
    nowpath1 = path_traindata + '/' + subject
    path2 = os.listdir(nowpath1)
    for emotion in path2:
        nowpath2 = nowpath1 + '/' + emotion
        path3 = os.listdir(nowpath2)
        for sentence in path3:
            filepath = nowpath2 + '/' + sentence
            # 获取文件名中的标签(情绪类型)
            Q = (filepath[28] + filepath[29])
            
            imge = cv2.imread(filepath)  # 读取图像
            face = detector(imge, 0)  # 检测人脸
            list = []
            landmarks = []
            if(len(face) == 0):
                continue
            if(len(face) == 1):
                for k, d in enumerate(face):
                    # 获取关键点
                    for p in predictor(imge, d).parts():
                        landmarks.append(p)
                    # 计算人脸特征距离
                    list.append(math.sqrt((landmarks[17].x - landmarks[21].x) ** 2 + (landmarks[17].y - landmarks[21].y) ** 2))
                    list.append(math.sqrt((landmarks[22].x - landmarks[26].x) ** 2 + (landmarks[22].y - landmarks[26].y) ** 2))
                    list.append(math.sqrt((landmarks[36].x - landmarks[39].x) ** 2 + (landmarks[36].y - landmarks[39].y) ** 2))
                    list.append(math.sqrt((landmarks[42].x - landmarks[45].x) ** 2 + (landmarks[42].y - landmarks[45].y) ** 2))
                    list.append(math.sqrt((landmarks[31].x - landmarks[35].x) ** 2 + (landmarks[31].y - landmarks[35].y) ** 2))
                    list.append(math.sqrt((landmarks[48].x - landmarks[54].x) ** 2 + (landmarks[48].y - landmarks[54].y) ** 2))
                    list.append(math.sqrt((landmarks[1].x - landmarks[15].x) ** 2 + (landmarks[1].y - landmarks[15].y) ** 2))
                    list.append(math.sqrt((landmarks[2].x - landmarks[14].x) ** 2 + (landmarks[2].y - landmarks[14].y) ** 2))
                    list.append(math.sqrt((landmarks[3].x - landmarks[13].x) ** 2 + (landmarks[3].y - landmarks[13].y) ** 2))
                    list.append(math.sqrt((landmarks[4].x - landmarks[12].x) ** 2 + (landmarks[4].y - landmarks[12].y) ** 2))
                    list.append(math.sqrt((landmarks[5].x - landmarks[11].x) ** 2 + (landmarks[5].y - landmarks[11].y) ** 2))
                    list.append(math.sqrt((landmarks[6].x - landmarks[10].x) ** 2 + (landmarks[6].y - landmarks[10].y) ** 2))
                    list.append(math.sqrt((landmarks[7].x - landmarks[9].x) ** 2 + (landmarks[7].y - landmarks[9].y) ** 2))
                    x2.append(list)  # 加入特征数据
                    if 'N' in Q:
                        y2.append(0)  # 加入标签
                    if 'D' in Q:
                        y2.append(1)  # 加入标签
# 加载数据和预处理的代码继续
# 请注意,以下代码片段是上一个代码片段的延续

# 加载数据和预处理(续)
X_train, X_test, y_train, y_test = train_test_split(x2, y2, test_size=0.2, random_state=1)  # 划分训练集和测试集

# 将数据转换为numpy数组,并进行归一化处理
X_train = np.array(X_train) / 80
X_test = np.array(X_test) / 80
y_train = np.array(y_train)
y_test = np.array(y_test)

# 定义模型结构
model = Sequential()
model.add(Embedding(10000, 256, input_length=13))
model.add(Position_Embedding())
model.add(Dropout(0.2))
model.add(Attention(8, 16))
model.add(GlobalAveragePooling1D())
model.add(Dense(2, activation='softmax'))

# 编译模型
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 定义回调函数并训练模型
history = LossHistory()
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=20, batch_size=128, callbacks=[history])

# 绘制训练过程中的损失和准确率曲线
history.loss_plot('epoch')

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值