PyTorch深度学习实战(17)——多任务学习

news2024/12/28 18:40:16

PyTorch深度学习实战(17)——多任务学习

    • 0. 前言
    • 1. 多任务学习
      • 1.1 多任务学习基本概念
      • 1.2 多任务学习优势
    • 2. 模型与数据集分析
      • 2.1 模型分析
      • 2.2 数据集介绍
    • 3. 实现年龄估计和性别分类
    • 小结
    • 系列链接

0. 前言

多任务学习( Multi-Task Learning, MTL )是一种常见的机器学习方法,用于同时处理和学习多个相关任务。在传统的单任务学习中,通常需要为每个任务训练一个独立的模型,而多任务学习则通过共享模型的特征表示来同时学习多个任务。例如,根据我们在猫狗分类和关键点检测中所学习的,我们能够训练神经网络对给定图像中的人物年龄或性别进行单独的预测,但是,我们尚未考虑如何根据单个图像同时预测年龄和性别。根据同一图像进行多项预测在实际场景中非常重要,因为同一张照片可能被用于同时进行多项预测。在本节中,将介绍多任务学习的基本概念,并构建模型同时执行多个不同类型的任务,包括预测人物的性别和年龄。

1. 多任务学习

1.1 多任务学习基本概念

多任务学习能够同时处理和学习多个相关任务,将多个互相关联的任务联合训练,从而提高模型的泛化能力和效果,使用一个或多个输入用于预测几个不同输出。在多任务学习中,多个不同的任务使用同一网络模型,模型同时学习多个任务的知识,从而更好地利用训练数据进行训练。例如,在自动驾驶中,模型需要识别障碍物、规划路线、提供适量的油门/制动和转向等,通过考虑相同的输入集(来自多个传感器)实时完成这些任务。

1.2 多任务学习优势

多任务学习的优势在于任务之间的相互促进和共享知识。通过将任务之间的相关性和依赖关系引入到共享模型中,可以提高整体性能、泛化能力和数据效率:

  • 提升性能:通过共享底层特征表示,模型可以从不同任务中学习到更通用的特征,可以通过共享知识来提高任务的性能
  • 泛化能力增强:多任务学习可以通过在不同但相关的任务上进行联合训练,帮助模型学习到更广泛、更全局的特征,从而提高其泛化能力
  • 数据效率提高:当我们面对数据稀缺的情况时,多任务学习可以通过共享模型来利用任务之间的数据共享,提高数据的有效利用率
  • 鲁棒性增强:多任务学习可以通过在不同任务之间共享特征,提高模型的鲁棒性和抗干扰能力。当一个任务面临异常或缺失数据时,其他任务可以提供额外的信息帮助模型更好地应对

多任务学习的应用领域广泛,如自然语言处理、计算机视觉、语音识别等,通过多任务学习可以共享底层的语义表示,提高任务的整体效果。

2. 模型与数据集分析

2.1 模型分析

在本节中,我们将学习如何在单个前向传递中同时进行连续值预测和离散值(类别)预测。构建模型策略如下:

  • 导入相关库
  • 获取包含人物图像、性别和年龄信息的数据集
  • 预处理数据并创建训练和测试数据集
  • 构建模型:
    • 特征提取层使用预训练VGG19模型
    • 创建两个分支独立层,其中一层对应于年龄估计,另一层对应于性别分类
    • 每个输出分支都有不同的损失函数,年龄是一个连续值(计算 msemae 损失),而性别是一个分类值(计算交叉熵损失)
    • 对年龄估计损失和性别分类损失加权求
    • 通过反向传播优化权重值来最小化整体损失
  • 训练模型并预测新图像

2.2 数据集介绍

为了构建多分类模型,我们将使用 FairFace 数据集,FairFace 数据集是一个用于面部分析和人脸识别的多样性人脸数据集,由 FairFace 团队于 2019 年发布。FairFace 数据集的目标是提供一个包含多种族、性别和年龄的真实世界人脸图像集合,以便研究人员可以训练和评估面部识别算法在多样性群体中的表现。该数据集包含了 87,022 个标记的人脸图像,下载使用此数据集,提取码:cr6n

3. 实现年龄估计和性别分类

接下来,使用 PyTorch 实现多任务学习模型。

(1) 导入相关库:

import torch
import numpy as np, cv2, pandas as pd, time
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, models
device = 'cuda' if torch.cuda.is_available() else 'cpu'

(2) 加载下载完成的数据集,查看数据结构:

trn_df = pd.read_csv('fairface-labels-train.csv')
val_df = pd.read_csv('fairface-labels-val.csv')
print(trn_df.head())

输出结果如下所示:

          file  age  gender        race  service_test
0  train/1.jpg   59    Male  East Asian          True
1  train/2.jpg   39  Female      Indian         False
2  train/3.jpg   11  Female       Black         False
3  train/4.jpg   26  Female      Indian          True
4  train/5.jpg   26  Female      Indian          True

(3) 构建 GenderAgeClass 类,以文件名作为输入并返回相应的图像、性别和年龄。其中,年龄需要缩放,因为这是一个连续的数字,缩放数据以避免梯度消失,然后在后处理期间重新进行还原。

__init__ 方法中以图像的文件路径作为输入:

IMAGE_SIZE = 224
class GenderAgeClass(Dataset):
    def __init__(self, df, tfms=None):
        self.df = df
        self.normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], 
                                              std=[0.229, 0.224, 0.225])

使用 __len__ 方法返回输入中图像数量:

    def __len__(self):
        return len(self.df)

定义 __getitem__ 方法,获取给定位置 ix 的图像信息:

    def __getitem__(self, ix):
        f = self.df.iloc[ix].squeeze()
        file = f.file
        gen = f.gender == 'Female'
        age = f.age
        im = cv2.imread(file)
        im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
        return im, age, gen

编写图像预处理函数,包括调整图像大小、调整图像通道以及图像归一化:

    def preprocess_image(self, im):
        im = cv2.resize(im, (IMAGE_SIZE, IMAGE_SIZE))
        im = torch.tensor(im).permute(2,0,1)
        im = self.normalize(im/255.)
        return im[None]

创建 collate_fn 方法,该方法用于对批数据执行以下预处理:

  • 使用 process_image 方法处理每个图像
  • 缩放年龄(除以数据集中存在的最大年龄值——80),令所有值都介于 01 之间
  • 将性别转换为浮点值
  • 将图像、年龄和性别转换为张量对象并返回
    def collate_fn(self, batch):
        'preprocess images, ages and genders'
        ims, ages, genders = [], [], []
        for im, age, gender in batch:
            im = self.preprocess_image(im)
            ims.append(im)

            ages.append(float(int(age)/80))
            genders.append(float(gender))

        ages, genders = [torch.tensor(x).to(device).float() for x in [ages, genders]]
        ims = torch.cat(ims).to(device)

        return ims, ages, genders

(4) 定义训练和验证数据集以及数据加载器。

创建数据集:

trn = GenderAgeClass(trn_df)
val = GenderAgeClass(val_df)

构建数据加载器:

train_loader = DataLoader(trn, batch_size=32, shuffle=True, drop_last=True, collate_fn=trn.collate_fn)
test_loader = DataLoader(val, batch_size=32, collate_fn=val.collate_fn)
a,b,c, = next(iter(train_loader))
print(a.shape, b.shape, c.shape)
# torch.Size([32, 3, 224, 224]) torch.Size([32]) torch.Size([32])

(5) 定义模型、损失函数和优化器。

在函数 get_model() 中,加载预训练 VGG16 模型:

def get_model():
    model = models.vgg16(pretrained = True)

冻结加载的模型(指定参数 param.requires_grad = False):

    for param in model.parameters():
        param.requires_grad = False

使用自定义网络层替换 avgpool 层:

    model.avgpool = nn.Sequential(
        nn.Conv2d(512,512, kernel_size=3),
        nn.MaxPool2d(2),
        nn.ReLU(),
        nn.Flatten()
    )

构建名为 ageGenderClassifier 的神经网络类,以创建包含两个输出分支的神经网络:

    class ageGenderClassifier(nn.Module):
        def __init__(self):
            super(ageGenderClassifier, self).__init__()

定义中间层 intermediate

            self.intermediate = nn.Sequential(
                nn.Linear(2048,512),
                nn.ReLU(),
                nn.Dropout(0.4),
                nn.Linear(512,128),
                nn.ReLU(),
                nn.Dropout(0.4),
                nn.Linear(128,64),
                nn.ReLU(),
            )

定义 age_classifiergender_classifier

            self.age_classifier = nn.Sequential(
                nn.Linear(64, 1),
                nn.Sigmoid()
            )
            self.gender_classifier = nn.Sequential(
                nn.Linear(64, 1),
                nn.Sigmoid()
            )

在以上代码中,年龄预测层 age_classifier 和性别预测层 gender_classifier 均使用 sigmoid 激活,因为年龄输出是一个介于 01 之间的值,且性别输出是 01

定义前向传递方法 forward,使用网络层 age_classifiergender_classifier

        def forward(self, x):
            x = self.intermediate(x)
            age = self.age_classifier(x)
            gender = self.gender_classifier(x)
            return gender, age

使用自定义网络替换 VGG16 预训练模型分类器模块:

    model.classifier = ageGenderClassifier()

定义性别分类(二元交叉熵损失)和年龄预测( L1 损失)的损失函数。定义优化器并返回模型、损失函数和优化器:

    gender_criterion = nn.BCELoss()
    age_criterion = nn.L1Loss()
    loss_functions = gender_criterion, age_criterion
    optimizer = torch.optim.Adam(model.parameters(), lr= 1e-4)
    
    return model.to(device), loss_functions, optimizer

调用 get_model() 函数初始化变量中的值:

model, loss_functions, optimizer = get_model()

(6) 定义函数在训练数据集上进行训练并在测试数据集上进行验证。train_batch 方法将图像、性别、年龄、模型、优化器和损失函数的实际值作为输入来计算总损失。

使用适当的输入参数定义 train_batch() 方法:

def train_batch(data, model, optimizer, criteria):

指定训练模型,将优化器重置为 zero_grad,并计算年龄和性别的预测值:

    model.train()
    ims, age, gender = data
    optimizer.zero_grad()
    pred_gender, pred_age = model(ims) 

在计算年龄估计和性别分类对应的损失之前,获取用于年龄估计和性别分类的损失函数:

    gender_criterion, age_criterion = criteria
    gender_loss = gender_criterion(pred_gender.squeeze(), gender)
    age_loss = age_criterion(pred_age.squeeze(), age)

通过将 gender_lossage_loss 相加来计算整体损失,并通过优化模型的可训练权重执行反向传播以减少整体损失:

    total_loss = gender_loss + age_loss
    total_loss.backward()
    optimizer.step()
    return total_loss

validate_batch() 方法将图像、模型和损失函数以及年龄和性别的实际值作为输入,计算年龄和性别的预测值以及损失值。

使用所需的输入参数定义 vaidate_batch 函数:

def validate_batch(data, model, criteria):

指定模型处于评估阶段,因此不需要进行梯度计算:

    model.eval()
    ims, age, gender = data
    with torch.no_grad():
        pred_gender, pred_age = model(ims)

计算年龄和性别预测对应的损失值( gender_lossage_loss)。压缩预测形状 (batch size, 1),以便将其整形为与目标值相同的形状( batch size):

    gender_criterion, age_criterion = criteria
    gender_loss = gender_criterion(pred_gender.squeeze(), gender)
    age_loss = age_criterion(pred_age.squeeze(), age)

计算整体损失,最终预测的性别类别( pred_gender)、性别预测准确率和年龄估计误差:

    total_loss = gender_loss + age_loss
    pred_gender = (pred_gender > 0.5).squeeze()
    gender_acc = (pred_gender == gender).float().sum()
    age_mae = torch.abs(age - pred_age).float().sum()
    return total_loss, gender_acc, age_mae

(7) 训练模型。

定义用于存储训练和测试损失值的列表,并指定训练 epoch 数:

model, criteria, optimizer = get_model()
val_gender_accuracies = []
val_age_maes = []
train_losses = []
val_losses = []

n_epochs = 10
best_test_loss = 1000
start = time.time()

在每个 epoch 开始时重新初始化训练和测试损失值:

for epoch in range(n_epochs):
    epoch_train_loss, epoch_test_loss = 0, 0
    val_age_mae, val_gender_acc, ctr = 0, 0, 0
    _n = len(train_loader)

遍历训练数据加载器( train_loader )并训练模型:

    for ix, data in enumerate(train_loader):
        # if ix == 100: break
        loss = train_batch(data, model, optimizer, criteria)
        epoch_train_loss += loss.item()

遍历测试数据加载器并计算性别及年龄预测准确率:

    for ix, data in enumerate(test_loader):
        # if ix == 10: break
        loss, gender_acc, age_mae = validate_batch(data, model, criteria)
        epoch_test_loss += loss.item()
        val_age_mae += age_mae
        val_gender_acc += gender_acc
        ctr += len(data[0])

计算年龄预测和性别分类的整体准确率:

    val_age_mae /= ctr
    val_gender_acc /= ctr
    epoch_train_loss /= len(train_loader)
    epoch_test_loss /= len(test_loader)

打印每个 epoch 结束时模型性能指标:

    elapsed = time.time()-start
    best_test_loss = min(best_test_loss, epoch_test_loss)
    print('{}/{} ({:.2f}s - {:.2f}s remaining)'.format(epoch+1, n_epochs, time.time()-start, (n_epochs-epoch)*(elapsed/(epoch+1))))
    info = f'''Epoch: {epoch+1:03d}\tTrain Loss: {epoch_train_loss:.3f}\tTest: {epoch_test_loss:.3f}\tBest Test Loss: {best_test_loss:.4f}'''
    info += f'\nGender Accuracy: {val_gender_acc*100:.2f}%\tAge MAE: {val_age_mae:.2f}\n'
    print(info)

存储每个 epoch 中测试数据集的年龄和性别预测准确率:

    val_gender_accuracies.append(val_gender_acc)
    val_age_maes.append(val_age_mae)

(8) 绘制年龄估计和性别预测训练过程中的准确率变化:

epochs = np.arange(1,len(val_gender_accuracies)+1)
fig,ax = plt.subplots(1,2,figsize=(10,5))
ax = ax.flat
ax[0].plot(epochs, val_gender_accuracies, 'bo')
ax[1].plot(epochs, val_age_maes, 'r')
ax[0].set_xlabel('Epochs')
ax[1].set_xlabel('Epochs')
ax[0].set_ylabel('Accuracy')
ax[1].set_ylabel('MAE')
ax[0].set_title('Validation Gender Accuracy')
ax[0].set_title('Validation Age Mean-Absolute-Error')
plt.show()

模型性能
在年龄预测方面平均与真实年龄相差了 6 岁左右,在性别预测方面的准确率约为 84%

(9) 随机选择测试图像,预测图中人物年龄和性别。

获取并加载图像,将其输入到 trn 对象中的 preprocess_image 方法中:

im = cv2.imread('4.jpeg')
im = trn.preprocess_image(im).to(device)

通过训练好的模型传递图像:

gender, age = model(im)
pred_gender = gender.to('cpu').detach().numpy()
pred_age = age.to('cpu').detach().numpy()

绘制图像并打印真实值和预测值:

im = cv2.imread('4.jpeg')
im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
plt.imshow(im)
plt.show()
print('predicted gender:',np.where(pred_gender[0][0]<0.5,'Male','Female'), '; Predicted age', int(pred_age[0][0]*80))
# predicted gender: Female ; Predicted age 26

综上,可以看到,我们能够一次性同时预测年龄和性别。但是,需要注意,本节中构建的模型非常不稳定,年龄值会随着图像的光照条件有很大差异,可以通过使用数据增强观察模型性能改善情况。

小结

多任务学习可以同时处理和学习多个相关任务,在实践中,通过在多个任务上进行联合训练,模型可以学习到更通用的特征表示,从而改善每个任务的性能,这种共享知识的方式可以减少对大量任务特定数据的需求,使得训练更加高效,同时任务之间的相互促进和共享知识可以帮助模型更好地理解数据的内在结构和模式。

系列链接

PyTorch深度学习实战(1)——神经网络与模型训练过程详解
PyTorch深度学习实战(2)——PyTorch基础
PyTorch深度学习实战(3)——使用PyTorch构建神经网络
PyTorch深度学习实战(4)——常用激活函数和损失函数详解
PyTorch深度学习实战(5)——计算机视觉基础
PyTorch深度学习实战(6)——神经网络性能优化技术
PyTorch深度学习实战(7)——批大小对神经网络训练的影响
PyTorch深度学习实战(8)——批归一化
PyTorch深度学习实战(9)——学习率优化
PyTorch深度学习实战(10)——过拟合及其解决方法
PyTorch深度学习实战(11)——卷积神经网络
PyTorch深度学习实战(12)——数据增强
PyTorch深度学习实战(13)——可视化神经网络中间层输出
PyTorch深度学习实战(14)——类激活图
PyTorch深度学习实战(15)——迁移学习
PyTorch深度学习实战(16)——面部关键点检测

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1024426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud Alibaba 整合Sentinel的基本使用

文章目录 一、什么是Sentinel二、Sentinel 的主要特性1. 流量控制&#xff1a;2. 熔断降级&#xff1a;3. 实时监控&#xff1a;4. 规则配置&#xff1a;5. 集成方便&#xff1a; 三、Sentinel 分为哪几部分:1. 核心库&#xff08;Java 客户端&#xff09;2. 控制台&#xff08…

Matlab图像处理-区域描述

一旦一幅图像的目标区域被确定&#xff0c;我们往往用一套描述子来表示其特性。选择区域描述子的动机不单纯为了减少在区域中原始数据的数量&#xff0c;而且也应有利于区别带有不同特性的区域。因此&#xff0c;当目标区域有大小、旋转、平移等方面的变化时&#xff0c;针对这…

ThreeJS-3D教学一基础场景创建

Three.js 是一个开源的 JS 3D 图形库&#xff0c;用于创建和展示高性能、交互式的 3D 图形场景。它建立在 WebGL 技术之上&#xff0c;并提供了丰富的功能和工具&#xff0c;使开发者可以轻松地构建令人惊叹的 3D 可视化效果。 Three.js 提供了一套完整的工具和 API&#xff0…

【深度学习】实验13 使用Dropout抑制过拟合

文章目录 使用Dropout抑制过拟合1. 环境准备2. 导入数据集3. 对所有数据的预测3.1 数据集3.2 构建神经网络 3.3 训练模型3.4 分析模型 4. 对未见过数据的预测4.1 划分数据集4.2 构建神经网络4.3 训练模型4.4 分析模型 5. 使用Dropout抑制过拟合5.1 构建神经网络5.2 训练模型5.3…

基于Qt4的拉格朗日插值实现及使用

目录 1 拉格朗日插值算法 2 实现思路 3 子程序编写 1 框架搭建 2 加载节点值 3 加载插值点 4 位置查找 5 二点线性插值 3 子程序使用 1 拉格朗日插值算法 拉格朗日插值是一种常用的散点插值算法,是是以法国十八世纪数学家约瑟夫拉格朗日命名的一种多项式插值方法。是…

python爬虫——爬取豆瓣top250电影数据(适合初学者)

前言&#xff1a; 爬取豆瓣top250其实是初学者用于练习和熟悉爬虫技能知识的简单实战项目&#xff0c;通过这个项目&#xff0c;可以让小白对爬虫有一个初步认识&#xff0c;因此&#xff0c;如果你已经接触过爬虫有些时间了&#xff0c;可以跳过该项目&#xff0c;选择更有挑…

Linux Shell 实现一键部署podman

podman 介绍 使用 Podman 管理容器、Pod 和映像。从本地环境中无缝使用容器和 Kubernetes&#xff0c;Podman 提供与 Docker 非常相似的功能&#xff0c;它不需要在你的系统上运行任何守护进程&#xff0c;并且它也可以在没有 root 权限的情况下运行。 Podman 可以管理和运行…

JavaWeb后端开发登录操作 登录功能 通用模板/SpringBoot整合

登录功能的思路 前端会传入两个参数:用户名和密码 在用户表中查询用户名,并校对相应的密码(涉及查询操作) SQL语句 select * from emp where username jingyong and password 123456; 如果有则成功,没有则登录失败.不可能为多个,因为添加了unique唯一约束,最终只会有一条 …

如何将转换器应用于时序模型

一、说明 在机器学习的广阔环境中&#xff0c;变压器作为建筑奇迹屹立不倒&#xff0c;以其复杂的设计和捕获复杂关系的能力重塑了我们处理和理解大量数据的方式。 自 2017 年创建第一台变压器以来&#xff0c;变压器类型呈爆炸式增长&#xff0c;包括强大的生成 AI 模型&#…

Kubernetes部署dolphindcheduler-3.1.8问题记录

温故知新 ⁉️问题记录❓问题一&#xff1a;Unschedulable 0/3 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod..❗解决方式&#xff1a;创建PV供应&#x1f…

ARM Soc内部总线

由于soc架构&#xff0c;把常用外设&#xff08;控制器&#xff09;集成到芯片内部&#xff0c;所以需要一种总线协调ARMcore与这些内部外设的通信&#xff0c;于是有了APB and AHB以及AXi这种片上总线。 同时要注意与常说的PC时代总线区分开&#xff1a; CPU总线&#xff08;…

刷题笔记24——完全二叉树的节点个数

有些事情是不能告诉别人的,有些事情是不必告诉别人的,有些事情是根本没有办法告诉别人的,而且有些事情是,即使告诉了别人,你也会马上后悔的。——罗曼罗兰 222. 完全二叉树的节点个数 java的幂运算要 (int) Math.pow(2,l1)-1计算满二叉树的节点数量公式&#xff1a;2 ^ height…

【面试题】—— Java多线程篇(17题)

文章目录 1.什么是多线程&#xff1f;2.线程和进程的区别&#xff1f;3.我们为什么要使用线程&#xff1f;线程的优缺点&#xff1f;4.创建线程的方法有哪些&#xff1f;5.线程的状态有哪些&#xff1f;6.线程的优先级&#xff1f;7.线程常用的方法以及其作用&#xff1f;8.使用…

穿越撒哈拉:中国跨境电商的非洲冒险之旅

非洲&#xff0c;这片古老而神秘的大陆&#xff0c;一直以来都是探险者和冒险家的梦想之地。然而&#xff0c;近年来&#xff0c;中国的跨境电商企业也开始将目光投向了这片充满机遇的土地&#xff0c;但他们的目标不再是黄金和珍宝&#xff0c;而是一个更为宝贵的财富&#xf…

创建线程的方式打开记事本

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 今天操作系统课老师讲到进程&#xff0c;提出了一个有趣的小实验&#xff1a;能否以系统调用的方式利用 Windows 创建进程的系统调用函数来打开一个软件。闲着蛋疼的我立马来了兴趣&#xff0c;姑且写一个玩…

跨平台编程开发工具Xojo 2023 Release mac中文版功能介绍

Xojo mac是一款跨平台的软件开发工具&#xff0c;它允许开发人员使用一种编程语言来创建应用程序&#xff0c;然后可以在多个操作系统上运行。Xojo 2023是Xojo开发工具的最新版本&#xff0c;它提供了许多功能和改进&#xff0c;以帮助开发人员更轻松地构建高质量的应用程序。 …

【洛谷】P2004 领地选择

原题链接&#xff1a;https://www.luogu.com.cn/problem/P2004 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 整体思路&#xff1a;二维前缀和 &#xff08;模板在这https://blog.csdn.net/m0_62531913/article/details/132712831?spm1001.2014.30…

[安洵杯 2019]easy_web md5强碰撞 preg_match绕过

比较简单 url一看就存在一个cmd 和 base64 我们尝试给cmd传递参数 但是没有效果 所以我们就去看看 img里面是什么 直接放到瑞士军刀看看 知道了加密方法 我们去看看能不能返回 index.php代码 TmprMlpUWTBOalUzT0RKbE56QTJPRGN3 返回了 接下俩就是代码审计了 <?php erro…

Python ---使用Fake库向clickhouse造数据小案例

每次insert太麻烦了 先在clickhosue中建表 test_user表 CREATE TABLE dwh.test_user (name String,age Int32,address String,phone String,email String ) ENGINE MergeTree() ORDER BY name; 此时表中暂无数据 用Python脚本来造一些数据 from faker import Faker from c…

Matlab图像处理-灰度级到彩色空间变换法

灰度级到彩色空间变换法 灰度图像转换为具有多种颜色渐变的连续彩色图像。该方法的基本概念是对任意输入像素的灰度级进行三个独立的变换。然后&#xff0c;将三个变换结果分别发送到彩电电视监视器的红、绿、蓝通道。该方法产生一个合成图像&#xff0c;其彩色内容受变换函数…