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

news2025/4/12 0:41:57

遗传算法与深度学习实战(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 random

import matplotlib.pyplot as plt
from livelossplot import PlotLossesKeras

dataset = 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.0

x_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 = 2

CONV_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 = 2

def 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 part

def generate_bn_layer():
    part = [BN_LAYER] 
    return part

def generate_pooling_layer():
    part = [POOLING_LAYER] 
    part.append(random.randint(min_pool, max_pool))
    part.append(random.randint(min_pool, max_pool))
    return part

def generate_dense_layer():
    part = [DENSE_LAYER] 
    part.append(generate_neurons())  
    return part

def generate_conv_layer():
    part = [CONV_LAYER] 
    part.append(generate_neurons())
    part.extend(generate_kernel())
    return part

def create_offspring():
    ind = []
    for i in range(max_layers):
        if random.uniform(0,1)<.5:
            #add convolution layer
            ind.extend(generate_conv_layer())
            if random.uniform(0,1)<.5:
                #add batchnormalization
                ind.extend(generate_bn_layer())
            if random.uniform(0,1)<.5:
                #add max pooling layer
                ind.extend(generate_pooling_layer())
    ind.extend(generate_dense_layer())
    return ind
        
individual = create_offspring()
print(individual)

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

def build_model(individual):
    model = models.Sequential()
    il = len(individual)
    i = 0
    while i < il:
        if individual[i] == CONV_LAYER: 
            n = individual[i+1]
            k = (individual[i+2], individual[i+3])
            i += CONV_LAYER_LEN
            if 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 layer
            k = k = (individual[i+1], individual[i+2])
            i += POOLING_LAYER_LEN
            model.add(layers.MaxPooling2D(k, padding="same"))      
        elif individual[i] == BN_LAYER: #add batchnormal layer
            model.add(layers.BatchNormalization())
            i += 1      
        elif individual[i] == DENSE_LAYER: #add dense layer
            model.add(layers.Flatten())      
            model.add(layers.Dense(individual[i+1], activation='relu'))
            i += 2
    model.add(layers.Dense(10))
    return model

model = 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] = ch2
    ind2[iv2:iv2+ll] = ch1
    return 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 individuals
        ind = 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 = .3

pop = 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)——编码卷积神经网络架构

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

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

相关文章

react-dnd 拖拽事件与输入框的文本选中冲突

问题描述 当我们使用拖拽库的时候&#xff0c;往往会遇到拖拽的一个元素他的子孙元素有输入框类型的dom节点&#xff0c;当拖拽的事件绑定在该元素身上时候&#xff0c;发现子孙的输入框不能进行文本选中了&#xff0c;会按住鼠标去选中文本的时候会触发拖拽 实际的效果&…

经典NLP案例 | 推文评论情绪分析:从数据预处理到模型构建的全面指南

NLP经典案例&#xff1a;推文评论情绪提取 项目背景 “My ridiculous dog is amazing.” [sentiment: positive] 由于所有推文每秒都在传播&#xff0c;很难判断特定推文背后的情绪是否会影响一家公司或一个人的品牌&#xff0c;因为它的病毒式传播&#xff08;积极&#xff0…

杨振宁大学物理视频中黄色的字,c#写程序去掉(原版改进,三)

上一节&#xff0c;我们分清了主次矛盾&#xff0c;并搞定了主要矛盾&#xff08;去掉黄色的字&#xff09;&#xff0c;这一节解决次要矛盾&#xff08;矩形色带&#xff09;。 我们的想法如图&#xff1a; 1&#xff0c;我们找到稳定黄色的最左边&#xff0c;最右边两点&…

第24周:文献阅读

目录 摘要 Abstract 一、现有问题 二、提出方法 三、创新点 模型结构创新 强化学习与GAN结合 属性特征与通顺性优化 四、方法论 生成对抗网络&#xff08;GAN&#xff09; 强化学习&#xff08;RL&#xff09; 模型组件 五、实验研究 数据集 数据预处理 评价指…

SQL server学习05-查询数据表中的数据(上)

目录 一&#xff0c;基本格式 1&#xff0c;简单的SQL查询语句 2&#xff0c;关键字TOP 3&#xff0c;关键字DISTINCT 二&#xff0c;模糊查询 1&#xff0c;通配符 三&#xff0c;对结果集排序 1&#xff0c;不含关键字DISTINCT 2&#xff0c;含关键字DISTINCT 3&…

【Azure 架构师学习笔记】- Azure Function (1) --环境搭建和背景介绍

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Function 】系列。 前言 随着无服务计算的兴起和大数据环境中的数据集成需求&#xff0c; 需要使用某些轻量级的服务&#xff0c;来实现一些简单操作。因此Azure Function就成了微软云上的一个必不可少的组成部分。 …

KeepAlive与RouterView缓存

参考 vue动态组件&#xff1c;Component&#xff1e;与&#xff1c;KeepAlive&#xff1e; KeepAlive官网介绍 缓存之keep-alive的理解和应用 Vue3Vite KeepAlive页面缓存问题 vue多级菜单(路由)导致缓存(keep-alive)失效 vue3 router-view keeperalive对于同一路径但路径…

Linux:进程(环境变量、程序地址空间)

目录 冯诺依曼体系结构 操作系统 设计操作系统的目的 操作系统的管理 进程 PCB fork 进程状态 进程状态查看 僵尸进程 孤儿进程 进程优先级 查看、修改进程优先级命令 竞争、独立、并行、并发 进程切换 活动队列和运行队列 活动队列 过期队列 active指针…

希迪智驾持续亏损8.2亿:毛利率下滑,冲刺“自动驾驶矿卡第一股”

《港湾商业观察》黄懿 近日&#xff0c;希迪智驾&#xff08;湖南&#xff09;股份有限公司&#xff08;下称“希迪智驾”&#xff09;向港交所主板递交上市申请&#xff0c;联席保荐人为中金公司、中信建投国际、中国平安资本&#xff08;香港&#xff09;。 资料显示&#…

Rust之抽空学习系列(三)—— 编程通用概念(中)

Rust之抽空学习系列&#xff08;三&#xff09;—— 编程通用概念&#xff08;中&#xff09; 1、变量&可变性 在Rust中&#xff0c;变量默认是不可变的 fn main() {let x 5;println!("x is {}", x); }使用let来声明一个变量&#xff0c;此时变量默认是不可变…

OpenCV中的识别图片颜色并绘制轮廓

一、实验原理 使用OpenCV库在图像中识别和绘制特定颜色&#xff08;黄色&#xff09;的轮廓 二、实验代码 import cv2 import numpy as np# 读取图片并调整大小 img cv2.imread(./color_1.png) img cv2.resize(img,(600,600))# 将图片从BGR颜色空间转换到HSV颜色空间 img_h…

【Qt】qt基础

目录 一、使用Qt Creator创建qt项目 二、项目文件解析 三、Qt中创建图形化界面的程序的两种方法 四、对象树 五、Qt中处理打印乱码问题的利器&#xff1a;qDebug() 一、使用Qt Creator创建qt项目 1.选择项目模板 选中第一类模板Application(Qt应用程序&#xff0c;包含普…

Transformer入门(6)Transformer编码器的前馈网络、加法和归一化模块

文章目录 7.前馈网络8.加法和归一化组件9.组合所有编码器组件构成完整编码器 7.前馈网络 编码器块中的前馈网络子层如下图所示&#xff1a; 图1.32 – 编码器块 前馈网络由两个带有ReLU激活函数的全连接层组成。全连接层&#xff08;Fully Connected Layer&#xff09;有时也…

AI智算-k8s部署大语言模型管理工具Ollama

文章目录 简介k8s部署OllamaOpen WebUI访问Open-WebUI 简介 Github&#xff1a;https://github.com/ollama/ollama 官网&#xff1a;https://ollama.com/ API&#xff1a;https://github.com/ollama/ollama/blob/main/docs/api.md Ollama 是一个基于 Go 语言开发的可以本地运…

HTML/CSS总结

HTML 1.1 标题标签h 为了使网页更具有语义化&#xff0c;我们经常会在页面中用到标题标签&#xff0c;HTML提供了6个等级的标题&#xff0c;即 标题标签语义&#xff1a; 作为标题使用&#xff0c;并且依据重要性递减 其基本语法格式如下&#xff1a; <h1> 标题文本…

信号处理:概念、技术、领域

目录 基本概念 主要技术 应用领域 信号处理是一个涉及分析、修改和再生信号的多学科领域。信号可以是各种形式的&#xff0c;例如声音、图像、视频或其他类型的监测数据。信号处理的主要目标是提取有用的信息并增强信号的质量。以下是信号处理的一些基本概念和应用&#xff…

黑盒白盒测试

任务1 黑盒测试之等价类划分法 【任务需求】 【问题】例&#xff1a;某报表处理系统要求用户输入处理报表的日期&#xff0c;日期限制在2003年1月至2008年12月&#xff0c;即系统只能对该段期间内的报表进行处理&#xff0c;如日期不在此范围内&#xff0c;则显示输入错误信息…

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

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

Go 怎么做性能优化芝麻开门篇

一、性能优化的流程 我们在对某个功能&#xff08;或单个接口&#xff09;做性能优化的时候。一般是该功能&#xff08;或接口&#xff09;性能无法满足我们的业务要求&#xff0c;所以被迫优化。在开始优化之前&#xff0c;我们需要明白一些理论知识。 1、常见的性能优化指标…

【Elasticsearch入门到落地】4、Elasticsearch的安装

接上篇《3、es与mysql的概念对比》 上一篇我们学习了Elasticsearch与Mysql的概念与区别。本篇我们来进行Elasticsearch的环境准备及软件安装。 一、环境准备 如果我们没有自己的Linux服务器&#xff0c;且现在正在使用的是Windows操作系统的电脑&#xff0c;那么首先我们需要安…