当前位置: 首页 > news >正文

遗传算法与深度学习实战(27)——进化卷积神经网络

遗传算法与深度学习实战(27)——进化卷积神经网络

    • 0. 前言
    • 1. 自定义交叉算子
    • 2. 自定义突变操作符
    • 3. 进化卷积神经网络
    • 小结
    • 系列链接

0. 前言

DEAP toolbox 中提供的标准遗传操作符对于自定义的网络架构基因序列来说是不够的。这是因为任何标准的交叉算子都可能破坏卷积神经网络 (Convolutional Neural Network, CNN) 的基因序列的格式。相反,为了构建进化卷积神经网络,我们需要为交叉和突变都构建自定义遗传算子。在本节中,我们首先介绍如何自定义交叉和突变算子,然后基于自定义遗传算子,构建进化卷积神经网络 (Evolutionary Convolutional Neural Network, EvoCNN)。

1. 自定义交叉算子

下图展示了如何将自定义交叉算子应用于父代双亲,该操作通过将两个父本中的各种层集合提取到不同列表中——一个用于卷积,一个用于池化等等。从每个列表中,随机选择一对层进行基因序列之间的交换,生成的基因序列为后代基因。

交叉算子

这只是执行交叉操作的一种方式,我们也可以考虑使用其他方式,重要的是保证在交叉操作后基因序列保持正确的格式。

(1) 首先,导入所需库、超参数、数据集以及辅助函数:

import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import numpy as np
import math
import time
import randomimport matplotlib.pyplot as plt
from livelossplot import PlotLossesKerasdataset = datasets.fashion_mnist
(x_train, y_train), (x_test, y_test) = dataset.load_data()# normalize and reshape data
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1).astype("float32") / 255.0
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1).astype("float32") / 255.0x_train = x_train[:1000]
y_train= y_train[:1000]
x_test = x_test[:100]
y_test= y_test[:100]class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat','Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']def plot_data(num_images, images, labels):grid = math.ceil(math.sqrt(num_images))plt.figure(figsize=(grid*2,grid*2))for i in range(num_images):plt.subplot(grid,grid,i+1)plt.xticks([])plt.yticks([])plt.grid(False)     plt.imshow(images[i].reshape(28,28))plt.xlabel(class_names[labels[i]])      plt.show()plot_data(25, x_train, y_train)max_layers = 5
max_neurons = 128
min_neurons = 16
max_kernel = 5
min_kernel = 2
max_pool = 3
min_pool = 2CONV_LAYER = -1
CONV_LAYER_LEN = 4
POOLING_LAYER = -2
POOLING_LAYER_LEN = 3
BN_LAYER = -3
BN_LAYER_LEN = 1
DENSE_LAYER = -4
DENSE_LAYER_LEN = 2def generate_neurons():return random.randint(min_neurons, max_neurons)def generate_kernel():part = []part.append(random.randint(min_kernel, max_kernel))part.append(random.randint(min_kernel, max_kernel))return partdef generate_bn_layer():part = [BN_LAYER] return partdef generate_pooling_layer():part = [POOLING_LAYER] part.append(random.randint(min_pool, max_pool))part.append(random.randint(min_pool, max_pool))return partdef generate_dense_layer():part = [DENSE_LAYER] part.append(generate_neurons())  return partdef generate_conv_layer():part = [CONV_LAYER] part.append(generate_neurons())part.extend(generate_kernel())return partdef create_offspring():ind = []for i in range(max_layers):if random.uniform(0,1)<.5:#add convolution layerind.extend(generate_conv_layer())if random.uniform(0,1)<.5:#add batchnormalizationind.extend(generate_bn_layer())if random.uniform(0,1)<.5:#add max pooling layerind.extend(generate_pooling_layer())ind.extend(generate_dense_layer())return indindividual = create_offspring()
print(individual)

(2) 定义函数 build_model() 用于根据基因创建神经网络模型:

def build_model(individual):model = models.Sequential()il = len(individual)i = 0while i < il:if individual[i] == CONV_LAYER: n = individual[i+1]k = (individual[i+2], individual[i+3])i += CONV_LAYER_LENif i == 0: #first layer, add input shape      model.add(layers.Conv2D(n, k, activation='relu', padding="same", input_shape=(28, 28, 1)))      else:model.add(layers.Conv2D(n, k, activation='relu', padding="same"))    elif individual[i] == POOLING_LAYER: #add pooling layerk = k = (individual[i+1], individual[i+2])i += POOLING_LAYER_LENmodel.add(layers.MaxPooling2D(k, padding="same"))      elif individual[i] == BN_LAYER: #add batchnormal layermodel.add(layers.BatchNormalization())i += 1      elif individual[i] == DENSE_LAYER: #add dense layermodel.add(layers.Flatten())      model.add(layers.Dense(individual[i+1], activation='relu'))i += 2model.add(layers.Dense(10))return modelmodel = build_model(individual) 

(3) get_layers() 函数用于从每个基因序列中提取网络层索引,可以使用一个列表推导式来完成此任务,通过检查序列中的每个值并提取列表中的匹配位置:

def get_layers(ind, layer_type):return [a for a in range(len(ind)) if ind[a] == layer_type]

(4) swap() 它负责交换每个个体的网络层块。swap() 函数通过从给定索引处提取序列中的每个网络层块进行交换。由于网络层类型的长度始终相同,因此可以简单的使用索引替换。需要注意的是,如果网络层块长度可变,就需要使用其它复杂的解决方案:

def swap(ind1, iv1, ind2, iv2, ll):ch1 = ind1[iv1:iv1+ll]ch2 = ind2[iv2:iv2+ll]print(ll, iv1, ch1, iv2, ch2)ind1[iv1:iv1+ll] = ch2ind2[iv2:iv2+ll] = ch1return ind1, ind2

(5) swap_layers() 函数是从序列中提取每种网络层类型并进行随机交换的地方,首先根据每个序列获取网络层的类型列表,c1c2 都是索引列表,通过循环确定交换点。从这些列表中,我们随机选择一个值来交换每个序列,并使用 swap() 函数执行交换:

def swap_layers(ind1, ind2, layer_type, layer_len):c1, c2 = get_layers(ind1, layer_type), get_layers(ind2, layer_type) min_c = min(len(c1), len(c2))for i in range(min_c):if random.random() < 1:i1 = random.randint(0, len(c1)-1)i2 = random.randint(0, len(c2)-1)      iv1 = c1.pop(i1)iv2 = c2.pop(i2)    ind1, ind2 = swap(ind1, iv1, ind2, iv2, layer_len) return ind1, ind2 

(6) 交叉函数 crossover() 为每组网络层调用 swap_layers() 函数:

def crossover(ind1, ind2):ind1, ind2 = swap_layers(ind1, ind2, CONV_LAYER, CONV_LAYER_LEN)ind1, ind2 = swap_layers(ind1, ind2, POOLING_LAYER, POOLING_LAYER_LEN)ind1, ind2 = swap_layers(ind1, ind2, BN_LAYER, BN_LAYER_LEN)ind1, ind2 = swap_layers(ind1, ind2, DENSE_LAYER, DENSE_LAYER_LEN)return ind1, ind2 ind1 = create_offspring()
ind2 = create_offspring()
print(ind1)
print(ind2)ind1, ind2 = crossover(ind1, ind2)
print(ind1)
print(ind2)

下图展示了在两个父代上执行 crossover() 函数后的结果,从中可以看出,交换了三个卷积层、一个池化层、一个批归一化层和一个全连接层组。

交叉结果

(7) 构建、编译、训练生成的个体,并输出结果。观察输出结果,确保交叉操作不会破坏基因序列的格式。现在,我们已经有了用于交叉和产生后代的交叉算子,接下来,将继续研究突变算子:

model = build_model(ind2) model.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy'])history = model.fit(x_train, y_train, epochs=3, validation_data=(x_test, y_test),callbacks=[PlotLossesKeras()],verbose=0)model.summary()
model.evaluate(x_test, y_test)

2. 自定义突变操作符

DEAP 中提供的标准变异操作符对于我们的自定义基因序列是无效的。因此,我们需要自定义变异操作符来模拟对基因序列应用的突变操作。在本节中,我们保持突变相对简单,只改变当前的网络层块。在更高级的应用中,突变可以删除或添加新的网络层块。

(1) 突变函数 mutation() 首先检查个体是否为空,如果不为空,对每个网络层组执行突变。最后,按照 DEAP 约定,以元组形式返回结果:

def mutate(part, layer_type):if layer_type == CONV_LAYER and len(part)==CONV_LAYER_LEN:part[1] = int(part[1] * random.uniform(.9, 1.1))part[2] = random.randint(min_kernel, max_kernel)part[3] = random.randint(min_kernel, max_kernel)elif layer_type == POOLING_LAYER and len(part)==POOLING_LAYER_LEN:part[1] = random.randint(min_kernel, max_kernel)part[2] = random.randint(min_kernel, max_kernel)elif layer_type == DENSE_LAYER and len(part)==DENSE_LAYER_LEN:part[1] = int(part[1] * random.uniform(.9, 1.1)) else:error = f"mutate ERROR {part}"    raise Exception(error) return part

(2) mutate_layers() 函数循环遍历特定类型的网络层组,并仅相应的超参数发生突变。首先使用 get_layers() 函数提取给定类型的网络层组索引。然后,在 try/except 块中,通过调用 mutate() 函数替换给定索引的网络层块应用突变:

def mutate_layers(ind, layer_type, layer_len):layers = get_layers(ind1, layer_type)for layer in layers:if random.random() < 1:try:ind[layer:layer+layer_len] = mutate(ind[layer:layer+layer_len], layer_type) except:print(layers)return ind      

(3) mutate() 函数首先检查提取的部分是否具有正确的长度,这是为了防止个体发生潜在的格式损坏问题。接下来,根据网络层类型,可以改变滤波器的数量和卷积核大小。需要注意的是,我们将卷积核大小限制在给定最小/最大范围内的值,但允许滤波器的数量增加或减少。此时,还检查个体基因序列是否有任何损坏的块,即不匹配所需长度的块。如果在突变过程中发现基因序列损坏,则会抛出异常,异常会在 mutation() 函数中捕获到:

def mutation(ind):  if len(ind) > CONV_LAYER_LEN: #only mutate conv individualsind = mutate_layers(ind, CONV_LAYER, CONV_LAYER_LEN)ind = mutate_layers(ind, DENSE_LAYER, DENSE_LAYER_LEN)ind = mutate_layers(ind, POOLING_LAYER, POOLING_LAYER_LEN)return ind,print(ind1)
ind1 = mutation(ind1)[0]
print(ind1)

下图显示了在个体基因序列上执行突变函数的结果。可以看到,只有定义网络层组的滤波器数量或卷积核大小的超参数被修改。

突变算子

构建、编译和训练突变的基因序列,以确认我们仍然可以生成一个有效的 Keras 模型。多次执行突变操作,以确认输出的基因序列是有效的。我们已经学习了构建用于处理交叉和突变操作的自定义运算符,接下来,我们继续应用进化算法。
Keras 的模型编译具有健壮性和宽容性,这在我们随机构建的一些模型可能存在问题并且无法产生良好结果时非常有用。相比之下,像 PyTorch 这样的框架宽容性较差,并且可能会对构建问题提产生阻塞错误。使用 Keras,我们可以进行最小的错误处理,因为大多数模型都可以运行;然而,它们可能运行效果不佳。如果我们在 PyTorch 上应用相同的进化算法,可能会遇到更多的构建问题,因为它对一些较小的问题也非常敏感,导致更少的后代幸存下来。相反,Keras 将产生更多可行的后代,可能发展成为更合适的解决方案。

3. 进化卷积神经网络

我们已经了解了自定义运算符的工作原理,在本节中,我们将其扩展为执行进化架构搜索,实现进化卷积神经网络 (Evolutionary Convolutional Neural Network, EvoCNN)。

(1) 设置 DEAP toolbox,重用 create_offspring() 函数,并在 toolbox 注册为 network,用于创建新的后代。然后,使用列表来保存个体基因序列,使用列表能够创建一组基因长度不同的个体:

creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)toolbox = base.Toolbox()
toolbox.register("network", create_offspring)
toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.network)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)toolbox.register("select", tools.selTournament, tournsize=5)

(2) 注册自定义的交叉和突变函数:

toolbox.register("mate", crossover)
toolbox.register("mutate", mutation)

(3) 训练网络,在 compile_train() 函数中,将训练固定为 3epochs

def clamp(num, min_value, max_value):return max(min(num, max_value), min_value)def compile_train(model):model.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),metrics=['accuracy'])model.fit(x_train, y_train, epochs=3,                     verbose=0)return model

(4) 构建、编译、训练并评估模型。evaluate() 函数首先使用 build_model() 函数构建模型,然后使用 compile_train() 函数编译和训练模型,之后,返回值 1/accuracy (accuracy 范围在 01 之间),这样做是因为我们希望通过 1/accuracy 来最小化适应度。需要注意的是,使用 try/except 语句将代码包装起来,以确保在任何失败情况下都能优雅地恢复。由于代码仍然可能构建出毫无意义的模型,使用 try/except 语句可以防止失败。如果模型构建失败,返回 1/.5。通过这种方式,能够将这些失败个体保留在种群中,并在之后突变为更好的解决方案:

def evaluate(individual):  try:model = build_model(individual)model = compile_train(model)print('.', end='')    return 1/clamp(model.evaluate(x_test, y_test, verbose=0)[1], .00001, 1),except:return 1/.5,  toolbox.register("evaluate", evaluate)   

适者生存,通过给失败的个体一定的基础适应度,使这些基因序列有机会留在种群池中。

(5) 设置进化过程,并可视化进化输出,由于基因序列相对较小,通常可以快速收敛,准确率大约为 81%。可以尝试增加种群的规模或代数的数量,查看其对结果的影响:

MU = 10 #@param {type:"slider", min:5, max:1000, step:5}
NGEN = 5 #@param {type:"slider", min:5, max:100, step:1}
RGEN = 1 #@param {type:"slider", min:1, max:100, step:1}
CXPB = .6
MUTPB = .3pop = toolbox.population(n=MU)
hof = tools.HallOfFame(1)
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", np.mean)
stats.register("std", np.std)
stats.register("min", np.min)
stats.register("max", np.max)best = None
groups = { "fitness" : {"min", "max"}}
plotlosses = PlotLosses(groups=groups)for g in range(NGEN):pop, logbook = algorithms.eaSimple(pop, toolbox, cxpb=CXPB, mutpb=MUTPB, ngen=RGEN, stats=stats, halloffame=hof, verbose=False)best = hof[0] print(f"Gen ({(g+1)*RGEN})")      for l in logbook:plotlosses.update({'min': 1/l["max"], 'max': 1/l["min"]})plotlosses.send()  # draw, update logs, etc

运行结果

(6) 进化完成后,构建、编译和训练最佳个体,查看结果,可以看到在 3epochs 后模型仍存在过拟合情况,这表明如果我们想要一个泛化能力更高的模型,可能需要增加训练 epochs,但会极大的增加演化时间:

build_compile_train(best, epochs=5)

运行结果

我们可以根据需要修改代码,并添加优化超参数:

  • 数据集大小:在本节中,我们大幅减小了原始数据集的大小以减少运行时间。如果增加数据集的大小,相应的运行时间也会增加
  • 训练 epochs:在本节中,我们将训练限制为 3epochs。根据数据集规模,可能需要增加或减少 epochs
  • 层类型:在本节中,我们只使用了标准层类型,如卷积、池化、批归一化和全连接层。我们也可以添加不同的层类型,如 dropout,或增加全连接层的数量等
  • 交叉/突变:在本节中,我们实现了自定义交叉和突变运算符。除了这种方式外,我们仍有进一步定制化的空间,例如在突变过程中添加或删除网络层块
  • 适应度/评估函数:本节中,个体的适应度基于准确率得分。如果我们想要最小化可训练参数或网络层数,也可以将其作为逻辑加入到 evaluate() 函数中

小结

卷积神经网络 (Convolutional Neural Network, CNN) 的设置和定义对于各种图像识别任务来说较为复杂的,通常得到最佳 CNN 超参数需要花费大量时间分析和调整。使用遗传算法进化一组个体,能够优化特定数据集上的 CNN 模型体系结构。本节中,介绍了自定义交叉和突变算子的构建方式,并使用自定义遗传算子实现进化卷积神经网络 (Evolutionary Convolutional Neural Network, EvoCNN)。

系列链接

遗传算法与深度学习实战(1)——进化深度学习
遗传算法与深度学习实战(2)——生命模拟及其应用
遗传算法与深度学习实战(3)——生命模拟与进化论
遗传算法与深度学习实战(4)——遗传算法(Genetic Algorithm)详解与实现
遗传算法与深度学习实战(5)——遗传算法中常用遗传算子
遗传算法与深度学习实战(6)——遗传算法框架DEAP
遗传算法与深度学习实战(7)——DEAP框架初体验
遗传算法与深度学习实战(8)——使用遗传算法解决N皇后问题
遗传算法与深度学习实战(9)——使用遗传算法解决旅行商问题
遗传算法与深度学习实战(10)——使用遗传算法重建图像
遗传算法与深度学习实战(11)——遗传编程详解与实现
遗传算法与深度学习实战(12)——粒子群优化详解与实现
遗传算法与深度学习实战(13)——协同进化详解与实现
遗传算法与深度学习实战(14)——进化策略详解与实现
遗传算法与深度学习实战(15)——差分进化详解与实现
遗传算法与深度学习实战(16)——神经网络超参数优化
遗传算法与深度学习实战(17)——使用随机搜索自动超参数优化
遗传算法与深度学习实战(18)——使用网格搜索自动超参数优化
遗传算法与深度学习实战(19)——使用粒子群优化自动超参数优化
遗传算法与深度学习实战(20)——使用进化策略自动超参数优化
遗传算法与深度学习实战(21)——使用差分搜索自动超参数优化
遗传算法与深度学习实战(22)——使用Numpy构建神经网络
遗传算法与深度学习实战(23)——利用遗传算法优化深度学习模型
遗传算法与深度学习实战(24)——在Keras中应用神经进化优化
遗传算法与深度学习实战(25)——使用Keras构建卷积神经网络
遗传算法与深度学习实战(26)——编码卷积神经网络架构

相关文章:

遗传算法与深度学习实战(27)——进化卷积神经网络

遗传算法与深度学习实战&#xff08;27&#xff09;——进化卷积神经网络 0. 前言1. 自定义交叉算子2. 自定义突变操作符3. 进化卷积神经网络小结系列链接 0. 前言 DEAP toolbox 中提供的标准遗传操作符对于自定义的网络架构基因序列来说是不够的。这是因为任何标准的交叉算子…...

【Vue3】前端使用 FFmpeg.wasm 完成用户视频录制,并对视频进行压缩处理

强烈推荐这篇博客&#xff01;非常全面的一篇文章&#xff0c;本文是对该博客的简要概括和补充&#xff0c;在不同技术栈中提供一种可行思路&#xff0c;可先阅读该篇文章再阅读本篇&#xff1a; FFmpeg——在Vue项目中使用FFmpeg&#xff08;安装、配置、使用、SharedArrayBu…...

基础算法——前缀和

由于比赛基本都是采用Dev-C所以&#xff0c;算法篇基本都是采用Dev-C来解释&#xff08;版本5.11&#xff0c;c11&#xff09; 首先介绍一下前缀和算法 给定一个数组&#xff0c;有q次询问&#xff0c;每次询问&#xff1a; 两个整数l,r&#xff0c;求出数组 l 到 r的结果 遇…...

spring实例化对象的几种方式(使用XML配置文件)

前言 Spring框架作为一个轻量级的控制反转&#xff08;IoC&#xff09;容器&#xff0c;为开发者提供了多种对象实例化的策略。通过这些策略&#xff0c;开发者可以更加灵活地控制对象的生命周期和依赖关系。无论是通过XML配置、注解配置还是Java配置&#xff0c;Spring都能…...

【二叉树】力扣 129.求根节点到叶子节点数字之和

一、题目 二、思路 每找到一个非空节点&#xff0c;之前路径上的所有节点的数量级都要增加1个单位。例如&#xff0c;当前节点为3&#xff0c;之前的节点路径为1 -> 2&#xff0c;presum 1 * 10 2 12&#xff0c;现在路径变为了 1 -> 2 -> 3&#xff0c;sum pres…...

深度学习物体检测之YOLOV5源码解读

V5比前面版本偏工程化,项目化,更贴合实战 一.V5版本项目配置 (1)整体项目概述 首先github直接查找yolov5&#xff0c;下载下来即可。在训练时&#xff0c;数据是怎么处理的&#xff1f;网络模型架构是怎么设计的(如各层的设计)&#xff1f;yolov5要求是大于python3.8与大于等…...

音频数据采样入门详解 - 给Python初学者的简单解释

音频数据采样入门详解 - 给Python初学者的简单解释 声音是如何变成数字的&#xff1f;什么是采样率&#xff1f;为什么要懂这个&#xff1f;Python小例子总结 大家好&#xff01;今天我们来聊一个有趣的话题&#xff1a;音频数据是如何在计算机中处理的。让我用最简单的方式来解…...

Unity类银河战士恶魔城学习总结(P179 Enemy Archer 弓箭手)

教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了敌人弓箭手的制作 Enemy_Archer.cs 核心功能 状态机管理敌人的行为 定义了多个状态对象&#xff08;如 idleState、moveState、attackState 等&#xff09;&#xff0c;通过状态机管理敌人的…...

SpringCloud集成sleuth和zipkin实现微服务链路追踪

文章目录 前言技术积累spring cloud sleuth介绍zipkin介绍Zipkin与Sleuth的协作 SpringCloud多模块搭建Zipkin Server部署docker pull 镜像启动zipkin server SpringCloud 接入 Sleuth 与 Zipkinpom引入依赖 (springboot2.6)appilication.yml配置修改增加测试链路代码 调用微服…...

Python随机抽取Excel数据并在处理后整合为一个文件

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;基于其中每一个文件&#xff0c;随机从其中选取一部分数据&#xff0c;并将全部文件中随机获取的数据合并为一个新的Excel表格文件的方法。 首先&#xff0c;我们来明确一下本文的具体需求。…...

Linux+Docker onlyoffice 启用 HTTPS 端口支持

文章目录 一、需求二、配置2.1 创建容器2.2 进入容器2.3 生成私钥和证书 2.4 测试访问 一、需求 上篇文章介绍了如何搭建一个 onlyoffice 在线预览服务&#xff0c;但是我们实际场景调用该服务的网站是协议是 https 的 &#xff0c;但是 onlyoffice 服务还没做配置&#xff0c…...

在 Visual Studio Code 中编译、调试和执行 Makefile 工程 llama2.c

在 Visual Studio Code 中编译、调试和执行 Makefile 工程 llama2.c 1. Installing the extension (在 Visual Studio Code 中安装插件)1.1. Extensions for Visual Studio Code1.2. C/C1.2.1. Pre-requisites 1.3. Makefile Tools 2. Configuring your project (配置项目)2.1.…...

python中math模块常用函数

文章目录 math模块简介各种三角函数反三角函数取整函数欧几里得距离绝对值最大公约数开根号幂阶乘函数 math模块简介 math模块是python标准库的一部分&#xff0c;提供了对于浮点数相关的数学运算&#xff0c;下面是常用的一些function 各种三角函数反三角函数 math.cos、ma…...

优化 Vue 3 开发体验:配置 Vite 使用 WebStorm 作为 Vue DevTools 的默认编辑器

优化 Vue 3 开发体验&#xff1a;配置 Vite 使用 WebStorm 替代 VS Code 作为 Vue DevTools 的默认编辑器 在 Vue 3 项目开发中&#xff0c;合理配置开发工具可以大大提升我们的工作效率。本文将介绍如何配置 Vite&#xff0c;使其在使用 Vue DevTools 时将默认编辑器从 VS Co…...

【C语言练习(9)—有一个正整数,求是几位数然后逆序打印】

C语言练习&#xff08;9&#xff09; 文章目录 C语言练习&#xff08;9&#xff09;前言题目题目解析结果总结 前言 主要到整数的取余(%)和整数的取商(/)&#xff0c;判断语句if…else if …else的使用 题目 给一个不多于3位的正整数&#xff0c;要求:一、求它是几位数&…...

热敏打印机的控制

首次接触热敏打印机&#xff0c;本来没有特别之处&#xff0c;花了大概十天时间完成一款猫学王热敏打印机&#xff0c;给到客户体验后&#xff0c;客户反馈说打字看起来不明显&#xff0c;打印照片有条纹&#xff0c;所以引起了我对于他的关注&#xff0c;几点不足之处需要优化…...

【closerAI ComfyUI】电商赋能,AI模特套图生产,各种姿势自定义,高度保持人物服饰场景一致性,摆拍街拍专用

closerAIGCcloserAI,一个深入探索前沿人工智能与AIGC领域的资讯平台,我们旨在让AIGC渗入我们的工作与生活中,让我们一起探索AIGC的无限可能性!aigc.douyoubuy.cn 【closerAI ComfyUI】电商赋能,AI模特套图生产,各种姿势自定义,高度保持人物服饰场景一致性,摆拍街拍专用…...

ARM学习(36)静态扫描规则学习以及工具使用

笔者来学习了解一下静态扫描以及其规则,并且亲身是实践一下对arm 架构的代码进行扫描。 1、静态扫描认识 静态扫描:对代码源文件按照一定的规则进行扫描,来发现一些潜在的问题或者风险,因为不涉及代码运行,所以其一般只是发现一些规范或则一些质量问题,当然这些可能存在潜…...

使用 Docker Compose 部署 Redis 主从与 Sentinel 高可用集群

文章目录 使用 Docker Compose 部署 Redis 主从与 Sentinel 高可用集群Redis 主从架构简介Redis Sentinel 简介配置文件1. 主节点配置 (redis-master.conf)2. 从节点配置 (redis-slave1.conf 和 redis-slave2.conf)redis-slave1.confredis-slave2.conf3. Sentinel 配置 (sentin…...

警惕!手动调整服务器时间可能引发的系统灾难

警惕&#xff01;手动调整服务器时间可能引发的系统灾难 1. 鉴权机制1.1 基于时间戳的签名验证1.2 基于会话的认证机制&#xff08;JWT、TOTP&#xff09; 2. 雪花算法生成 ID 的影响2.1 时间戳回拨导致 ID 冲突2.2 ID 顺序被打乱 3. 日志记录与审计3.1 日志顺序错误3.2 审计日…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

《Docker》架构

文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器&#xff0c;docker&#xff0c;镜像&#xff0c;k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...

一些实用的chrome扩展0x01

简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序&#xff0c;无论是测试应用程序、搜寻漏洞还是收集情报&#xff0c;它们都能提升工作流程。 FoxyProxy 代理管理工具&#xff0c;此扩展简化了使用代理&#xff08;如 Burp…...

云原生安全实战:API网关Envoy的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口&#xff0c;负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...