【深度学习】 零基础介绍卷积神经网络(CNN)

零基础介绍

卷积神经网络(CNN,Convolutional Neural Network)是深度学习中的一种神经网络,特别擅长处理图像和视频等有空间结构的数据。

假设我们在做一个“照片分类”的任务,比如判断一张照片中是猫还是狗。下面用一个通俗的例子来解释CNN的工作原理。

  1. 看图的方式:模拟人眼
    当我们看一张图片时,并不是从头到尾一口气看完的,而是我们的眼睛会专注于某个小区域,然后逐渐移到其他地方。CNN就是模仿这种“局部视野”的方式来处理图像。它通过滑动一个小窗口(称为“卷积核”)来查看图片的不同部分。

  2. 卷积层(Convolutional Layer)
    卷积层的作用就是使用多个卷积核对图像进行扫描。这些卷积核可以看作是一个小的滤镜,它们能提取图像中的特征。假设我们有一张猫的照片,卷积核可能会学习到猫的耳朵形状、眼睛的位置、毛发的纹理等特征。每次卷积操作之后,图像会变成一个包含这些特征的“特征图”(feature map)。

    例如,如果我们有一张3×3的卷积核(就是一个3×3的小矩阵),它会遍历图像的每个部分,计算卷积核和图片的局部区域的点积,产生一个新的值。这就像你用滤镜滤镜了一小块区域。

  3. 激活函数(ReLU)
    卷积层提取到特征之后,接下来会通过一个叫做ReLU(Rectified Linear Unit)的激活函数。ReLU会把负数变为零,保留正数。简单来说,就是“过滤”掉一些不重要的信息,保留对分类有帮助的特征。

  4. 池化层(Pooling Layer)
    池化层的作用是将卷积层生成的特征图进行下采样,减少图像的大小和计算量。通常有两种常用的池化方式:

    最大池化(Max Pooling):从每个小区域中选出最大的值。
    平均池化(Average Pooling):从每个小区域中计算平均值。

    池化的作用就是保留图像中最重要的信息,同时减少不必要的细节,就像是在提炼出最精华的部分。

  5. 全连接层(Fully Connected Layer)
    在经过多个卷积层和池化层之后,CNN会将图像的特征汇聚起来,传递到全连接层。这个层的作用类似于神经网络的最终决策阶段,负责根据之前提取到的特征做出最终的分类决策。比如根据猫耳朵、眼睛、毛发的纹理等信息,最终判断出这是猫还是狗。

  6. 输出层(Output Layer)
    最后,输出层会根据神经网络的结果给出分类结果。如果是猫,输出1;如果是狗,输出0。这个结果就是CNN根据图像学习到的特征做出的决策。

总结:
CNN通过逐层提取图像的特征,模拟人类如何观察图像,最终做出分类决策。它的优势在于能够自动学习图像中的有用特征,而不需要人工提取这些特征,这使得CNN特别适合图像处理任务。

比喻:
你可以把CNN想象成一个侦探,它通过从图片的各个细节(耳朵、眼睛、毛发等)收集线索,最终推理出这是一只猫还是狗。每一个卷积核就像是侦探手中的放大镜,帮助他专注于图片中的不同部分,池化层则是帮助侦探筛选出最重要的线索。最终,侦探通过这些线索得出了结论。

写个CNN最简单的代码

假设我们的输入图像是一个 3x3 的矩阵,卷积核(滤波器)是一个 2x2 的矩阵。

  1. 输入:
    1 2 3
    4 5 6
    7 8 9

  2. 卷积核(滤波器)
    1 0
    0 1

  3. 在卷积操作中,卷积核会在输入图像上滑动,并计算卷积核和当前区域的点积

    步骤:
    我们从输入图像的左上角开始,把卷积核放在图像的最左上角,然后计算卷积核与图像覆盖区域的点积。卷积核的每个元素与对应区域的每个元素相乘,然后求和。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  4. 结果
    通过这些卷积操作,我们得到了一个 2x2 的特征图(Feature Map):
    在这里插入图片描述

代码如下:

import numpy as np# 输入图像
image = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])# 卷积核(滤波器)
kernel = np.array([[1, 0],[0, 1]])# 输出特征图的尺寸
output_height = image.shape[0] - kernel.shape[0] + 1
output_width = image.shape[1] - kernel.shape[1] + 1# 创建一个空的输出特征图
output = np.zeros((output_height, output_width))# 执行卷积操作
for i in range(output_height):for j in range(output_width):# 计算当前区域的点积region = image[i:i+kernel.shape[0], j:j+kernel.shape[1]]output[i, j] = np.sum(region * kernel)print("卷积结果(特征图):")
print(output)

输出结果:

卷积结果(特征图):
[[ 6. 8.]
[12. 14.]]


接下来正式介绍CNN!
在这里插入图片描述

一. 概述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

二. 搭建CNN

在这里插入图片描述

1. 输入层

在这里插入图片描述

2. 卷积层

在这里插入图片描述

对于灰度图:
在这里插入图片描述
对于彩色图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 激活层

在这里插入图片描述

4. 池化层

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5. 全连接层

在这里插入图片描述

6. 网络搭建小结

在这里插入图片描述

7. 损失函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8. 梯度下降

在这里插入图片描述
在这里插入图片描述

8. 反向传播

在这里插入图片描述

在这里插入图片描述

9. 模型评估与正则化

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10. 尝试搭建自己的第一个CNN

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三. 经典CNN结构

在这里插入图片描述

在这里插入图片描述

四. 猫狗识别项目实践

1. Paddle实现版本:

import paddle
import paddle.fluid as fluid
import numpy as np
from PIL import Image
import sys
from multiprocessing import cpu_count
import matplotlib.pyplot as plt
import os
BATCH_SIZE = 128
# 用于训练的数据提供器
train_reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.cifar.train10(),buf_size = BATCH_SIZE * 100),batch_size = BATCH_SIZE)#用于测试的数据提供器
test_reader = paddle.batch(paddle.dataset.cifar.test10(),batch_size = BATCH_SIZE
)
def  convolutional_neural_network(img):# 第一个卷积 - 池化层conv1 = fluid.layers.conv2d(input= img, # 输入图像num_filters =20,      #卷积核的大小filter_size = 5,    #卷积核数量,它与输出的通道相同act = 'relu')     #激活函数pool1 = fluid.layers.pool2d(input = conv1,  # 输入pool_size = 2, #池化核大小pool_type = 'max', # 池化类型pool_stride = 2)  # 池化步长conv_pool_1 = fluid.layers.batch_norm(pool1)# 第二个卷积 - 池化层conv2 = fluid.layers.conv2d(input= conv_pool_1, # 输入图像num_filters =50,      #卷积核的大小filter_size = 5,    #卷积核数量,它与输出的通道相同act = 'relu')     #激活函数pool2 = fluid.layers.pool2d(input = conv2,  # 输入pool_size = 2, #池化核大小pool_type = 'max', # 池化类型pool_stride = 2)  # 池化步长conv_pool_2 = fluid.layers.batch_norm(pool2)# 第三个卷积 - 池化层conv3 = fluid.layers.conv2d(input= conv_pool_2, # 输入图像num_filters =50,      #卷积核的大小filter_size = 5,    #卷积核数量,它与输出的通道相同act = 'relu')     #激活函数pool3 = fluid.layers.pool2d(input = conv3,  # 输入pool_size = 2, #池化核大小pool_type = 'max', # 池化类型pool_stride = 2)  # 池化步长# 以softmax 为激活函数的全连接输出层,10类数据输出10个数字prediction = fluid.layers.fc(input = pool3,size = 10,act = 'softmax')return prediction
paddle.enable_static()
# 3 代表图像RGB三通道,32✖32的彩色图片
data_shape = [3,32,32]
# 定义全局变量 image 和 label 
images = fluid.layers.data(name = 'images',shape = data_shape,dtype = 'float32')
label = fluid.layers.data(name = 'label',shape=[1],dtype = 'int64')
# 获取分类器,用cnn分类
predict = convolutional_neural_network(images)
cost = fluid.layers.cross_entropy(input=predict,label = label)
avg_cost = fluid.layers.mean(cost)
acc = fluid.layers.accuracy(input=predict,label = label)
optimizer = fluid.optimizer.Adam(learning_rate =0.001)
optimizer.minimize(avg_cost)
place =  fluid.CUDAPlace(0)
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
feeder = fluid.DataFeeder(feed_list=[images,label],place = place)
EPOCH_NUM = 15
for pass_id in range(EPOCH_NUM):train_cost = 0for batch_id,data in enumerate(train_reader()):train_cost,train_acc = exe.run(program = fluid.default_main_program(),feed = feeder.feed(data),fetch_list =[avg_cost,acc])if batch_id % 100 ==0:print('Pass: %d, Batch: %d, Cost: %0.5f, Accuarcy: %0.5f'%(pass_id,batch_id,train_cost[0],train_acc[0]))test_costs = []test_accs = []for batch_id,data in enumerate(test_reader()):test_cost,test_acc = exe.run(program = fluid.default_main_program(),feed = feeder.feed(data),fetch_list = [avg_cost,acc])test_costs.append(test_cost[0])test_accs.append(test_acc[0])# 求测试结果的平均值test_cost = (sum(test_costs) / len(test_costs))                         #计算误差平均值(误差和/误差的个数)test_acc = (sum(test_accs) / len(test_accs))                            #计算准确率平均值( 准确率的和/准确率的个数)print('Test:%d, Cost:%0.5f, ACC:%0.5f' % (pass_id, test_cost, test_acc))model_save_dir = "/home/aistudio/data/catdog.inference.model"if not os.path.exists(model_save_dir):os.makedirs(model_save_dir)fluid.io.save_inference_model(model_save_dir,['images'],[predict],exe)
infer_exe = fluid.Executor(place)
inference_scope = fluid.core.Scope() 
def load_image(file):#打开图片im = Image.open(file)#将图片调整为跟训练数据一样的大小  32*32im = im.resize((32, 32), Image.ANTIALIAS)#建立图片矩阵 类型为float32im = np.array(im).astype(np.float32)#矩阵转置 im = im.transpose((2, 0, 1))                               #将像素值从【0-255】转换为【0-1】im = im / 255.0    im = np.expand_dims(im, axis=0)return im
with fluid.scope_guard(inference_scope):#从指定目录中加载 推理model(inference model)[inference_program, # 预测用的programfeed_target_names,  fetch_targets] = fluid.io.load_inference_model(model_save_dir,infer_exe)  infer_path='/home/aistudio/data/cat.png'img = Image.open(infer_path)plt.imshow(img)   plt.show()    img = load_image(infer_path)results = infer_exe.run(inference_program,               feed={feed_target_names[0]: img}, fetch_list=fetch_targets)        label_list = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse","ship", "truck"]print("infer results: %s" % label_list[np.argmax(results[0])])

在这里插入图片描述

2. Keras 和 TensorFlow实现版本

完整CNN代码:

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.optimizers import Adam# 构建一个简单的CNN模型
model = Sequential()# 第一个卷积层:使用32个3x3的卷积核,激活函数为ReLU,输入图像尺寸为64x64x3(RGB图像)
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(64, 64, 3)))# 第一个池化层:使用2x2的池化窗口,减少空间尺寸
model.add(MaxPooling2D(pool_size=(2, 2)))# 第二个卷积层:使用64个3x3的卷积核,激活函数为ReLU
model.add(Conv2D(64, (3, 3), activation='relu'))# 第二个池化层:同样使用2x2的池化窗口
model.add(MaxPooling2D(pool_size=(2, 2)))# 第三个卷积层:使用128个3x3的卷积核,激活函数为ReLU
model.add(Conv2D(128, (3, 3), activation='relu'))# 第三个池化层:同样使用2x2的池化窗口
model.add(MaxPooling2D(pool_size=(2, 2)))# 将3D的卷积输出展平为1D的向量
model.add(Flatten())# 添加一个全连接层:512个神经元,激活函数为ReLU
model.add(Dense(512, activation='relu'))# 添加一个Dropout层:随机丢弃30%的神经元,防止过拟合
model.add(Dropout(0.3))# 添加输出层:2个神经元(分类为猫或狗),使用Softmax激活函数
model.add(Dense(2, activation='softmax'))# 编译模型:使用Adam优化器,损失函数为交叉熵,评估指标为准确率
model.compile(optimizer=Adam(), loss='sparse_categorical_crossentropy', metrics=['accuracy'])# 打印模型总结,查看模型结构
model.summary()

代码逐行解释:
tensorflow 是深度学习的框架,keras 是其中的高级API,用于构建神经网络。
Sequential 是模型的线性堆叠结构,表示网络各层按顺序堆叠。
Conv2D 是卷积层,用于图像特征提取。
MaxPooling2D 是池化层,用于降维,减少计算量。
Flatten 是将多维数据转换为一维向量,方便进入全连接层。
Dense 是全连接层,用于决策输出。
Dropout 是一种正则化技术,随机丢弃神经元,防止模型过拟合。
Adam 是一种常用的优化算法,用于调整网络中的权重。

model = Sequential()

这行代码创建了一个空的 Sequential 模型,表示我们将按顺序添加各个网络层。

model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(64, 64, 3)))

Conv2D(32, (3, 3)):这是一个卷积层,使用 32 个 3x3 的卷积核。
activation=‘relu’:激活函数使用 ReLU(Rectified Linear Unit),它可以帮助模型引入非线性。
input_shape=(64, 64, 3):输入图像的大小为 64x64 像素,3 个颜色通道(RGB)。
卷积层的作用是通过卷积核对图像进行扫描,提取局部特征,如边缘、纹理等。

model.add(MaxPooling2D(pool_size=(2, 2)))

MaxPooling2D(pool_size=(2, 2)):这是一个池化层,使用 2x2 的窗口来对图像进行降维。池化层通常将图像的空间尺寸缩小一半,减少计算量,并保留最重要的特征。

model.add(Flatten())

Flatten():将卷积层和池化层输出的 3D 张量(如 64x64x128)展平成 1D 向量(如 512),准备输入到全连接层。

model.add(Dense(512, activation='relu'))

Dense(512):全连接层,包含 512 个神经元,每个神经元与前一层的每个神经元都有连接。
activation=‘relu’:使用 ReLU 激活函数。
全连接层的作用是结合从卷积层提取到的所有特征,进行更高层次的抽象和决策。

model.add(Dropout(0.3))

Dropout(0.3):这是一个 Dropout 层,随机丢弃 30% 的神经元,防止模型过拟合。过拟合是指模型过于依赖训练数据,导致对新数据的预测效果差。

model.add(Dense(2, activation='softmax'))

Dense(2):输出层,包含 2 个神经元,因为我们要分类的是 2 类(比如猫和狗)。
activation=‘softmax’:使用 Softmax 激活函数,它将输出转化为概率值,表示属于每个类别的概率。

model.compile(optimizer=Adam(), loss='sparse_categorical_crossentropy', metrics=['accuracy'])

optimizer=Adam():使用 Adam 优化器,自动调整学习率以最小化损失。
loss=‘sparse_categorical_crossentropy’:使用交叉熵作为损失函数,适用于多分类任务。
sparse 表示目标标签是整数。
metrics=[‘accuracy’]:我们会评估模型的准确率。

model.summary()

model.summary():输出模型的结构,显示各层的类型、输出形状和参数数量

提问检测环节

  1. CNN 的基本组成部分有哪些?
  2. 卷积层(Convolutional Layer):作用是什么?如何提取特征?
  3. 池化层(Pooling Layer):种类、作用及原理(如 MaxPooling 和 AveragePooling)。
  4. 为什么池化层没有参数?
  5. 激活函数(Activation Function):常见的 ReLU、Sigmoid、Softmax 等作用和区别。
  6. 全连接层(Fully Connected Layer):为什么需要展平(Flatten)?
  7. Dropout:在什么场景使用?如何防止过拟合?
  8. 简述 CNN 的基本组成部分及其功能。
  9. 什么是池化?它对特征图有何作用?
  10. SGD、Adam、RMSprop 的特点与适用场景。
  11. 准确率(Accuracy)、损失(Loss)、混淆矩阵(Confusion Matrix)的解读。
  12. 过拟合模型的表现特点。
  13. 为什么 Adam 优化器适合深层网络?

你都答对了吗?

感谢点赞关注👍

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Dual-Write Problem 双写问题(微服务)

原文链接https://www.confluent.io/blog/dual-write-problem/ 双写问题发生于当两个外部系统必须以原子的方式更新时。 问题 说有人到银行存了一笔钱,触发 DepositFunds 命令,DepositFunds 命令被发送到Account microservice。 Account microservice需…

ReactPress最佳实践—搭建导航网站实战

Github项目地址:https://github.com/fecommunity/easy-blog 欢迎Star。 近期,阮一峰在科技爱好者周刊第 325 期中推荐了一款开源工具——ReactPress,ReactPress一个基于 Next.js 的博客和 CMS 系统,可查看 demo站点。(…

什么叫ip地址一样?网络ip地址一样说明什么

在探索网络世界的奥秘中,IP地址作为网络设备的唯一身份标识,其重要性不言而喻。然而,当我们遇到“IP地址一样”的情况时,不禁会产生诸多疑问:这究竟意味着什么?是否会对网络产生影响?虎观代理小…

C# 探险之旅:第三十二节 - 类型class之(方法重载Overloading):魔法技能的大变身!

嘿,各位勇敢的探险家们!欢迎再次踏上C#的奇幻旅程。今天,我们要一起探索一个超级有趣的魔法技巧——方法重载(Overloading)!想象一下,你有一个超级技能,但是这个技能可以根据不同的情…

kubervirt使用与运行策略

三、KubeVirt基本命令 3.1查看virtctl版本&#xff0c;说明安装成功 [rootk8s-master ~]# virtctl version 3.2创建和管理虚拟机 列出所有可用的虚拟机实例 [rootmaster ~]# kubectl get vmi -n <namespace> 参数-n用于指定命名空间 查看特定虚拟机实例的详细信息 […

[Pro Git#3] 远程仓库 | ssh key | .gitignore配置

目录 1. 分布式版本控制系统的概念 2. 实际使用中的“中央服务器” 3. 远程仓库的理解 4. 新建远程仓库 5. 克隆远程仓库 6. 设置SSH Key 实验 一、多用户协作与公钥管理 二、克隆后的本地与远程分支对应 三、向远程仓库推送 四、拉取远程仓库更新 五、配置Git忽略…

【python因果库实战2】使用银行营销数据集研究营销决策的效果2

目录 联系方式的效应 逆概率加权&#xff1a;首次尝试 联系方式的效应 我们已经完成了大部分艰苦的工作&#xff0c;即理解数据并识别处理变量和混杂因素。现在我们可以开始使用 Causal Inference 360 的工具了。 我们将首先研究联系方式 contact 的因果效应。具体来说&…

数据结构初阶---二叉树---堆

一、树 1.树的概念 树是一种非线性的数据结构&#xff0c;由n(n≥0)个有限结点组成的一个有层次关系的集合。形状类似一棵倒挂的树&#xff0c;根朝上&#xff0c;分支向下。 根结点没有前驱结点&#xff0c;可以有n(n≥0)个后继结点。 其余结点被分为M个互不相交的集合&am…

运维 mysql、redis 、RocketMQ性能排查

MySQL查看数据库连接数 1. SHOW STATUS命令-查询当前的连接数 MySQL 提供了一个 SHOW STATUS 命令&#xff0c;可以用来查看服务器的状态信息&#xff0c;包括当前的连接数。 SHOW STATUS LIKE Threads_connected;这个命令会返回当前连接到服务器的线程数&#xff0c;即当前…

.NET6 WebAPI从基础到进阶--朝夕教育

1、环境准备 1. Visual Studio 2022 2. .NET6 平台支持 3. Internet Information Services 服务器&#xff08; IIS &#xff09; 4. Linux 服务器 【 CentOS 系统】 ( 跨平台部署使用 ) 5. Linux 服务器下的 Docker 容器&#xff08; Docker 部署使用&#xff09; …

STM32仿真——01创建工程

目录 1.需要用到的软件工具​编辑 2.第一步Proteus软件新建工程​编辑 3.第二步——stm32cubumx 4、MDK代码编写 #注意安装的过程或者使用过程使用英文&#xff0c;以防报错&#xff1b; 1.需要用到的软件工具 2.第一步Proteus软件新建工程 选中&#xff0c;默认 先布局&…

相位小数偏差(UPD)估计基本原理

PPP中的一个关键性难题在于非差模糊度固定&#xff0c;成功固定非差模糊度可以使 PPP 的收敛速度和定位精度得到显著提升 。 相位小数偏差 (UPD) 是致使相位模糊度失去整数特性的主要因素&#xff0c;精确估计并校正 UPD 是实现非差模糊度固定的重要前提&#xff0c;也是实现…

我们来编程 -- win11多jdk版本切换

题记 售前的酒喝到位了调研需求及文档整理出来了开发要入场了&#xff0c;真惨啊&#xff01;年底了&#xff0c;手里活干的好好的&#xff0c;因为flyback在项目地&#xff0c;硬是被安排进来了拥抱变化&#xff0c;我呸…不得不切换系统&#xff0c;构建代码&#xff0c;一股…

飞腾派4g版本笔记一

飞腾派4g版本开箱体验 开箱包裹内容 打开包装&#xff0c;你可以看到以下物品 一个绿联的usb3.0读卡器、sandisk的32g内存卡(太好了)飞腾派4g版本开发板带散热风扇&#xff08;通过DDR存储的丝印看到是长鑫存储&#xff0c;即为4g内存版本&#xff09;输出为12v 3A的电源适配…

从零用java实现 小红书 springboot vue uniapp (2)主页优化

前言 移动端演示 http://8.146.211.120:8081/#/ 前面的文章我们基本完成了主页的布局 今天我们具体的去进行实现 并且分享我开发时遇到的问题 首先先看效果 java仿小红书主页 实现效果为 1.顶端全屏切换 2.上划加载更多 3.下拉当前页整体刷新 顶端全屏切换我们选择 gui-switch…

3D 生成重建031-One-2-3-45多视图+Neus生成3D

3D 生成重建031-One-2-3-45多视图Neus生成3D* 文章目录 0 论文工作论文方法2 实验结果 0 论文工作 单图像三维重建是一项重要但极具挑战性的任务&#xff0c;需要对现实世界有深入的了解。许多现有的方法通过在二维扩散模型的引导下优化神经辐射场来解决这个问题&#xff0c;但…

JAVA:访问者模式(Visitor Pattern)的技术指南

1、简述 访问者模式(Visitor Pattern)是一种行为型设计模式,允许你将操作分离到不同的对象中,而无需修改对象本身的结构。这种模式特别适合复杂对象结构中对其元素进行操作的场景。 本文将介绍访问者模式的核心概念、优缺点,并通过详细代码示例展示如何在实际应用中实现…

【C++】数的性质问题分析与优化

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目解析与分析题目描述题目分析 &#x1f4af;我的解法与详细解读初始代码实现解法分析 &#x1f4af;老师解法与其改进思路老师代码实现改进与优势 &#x1f4af;对比分析…

让文案生成更具灵活性/chatGPT新功能canvas画布编辑

​ ​ OpenAI最近在2024年12月发布了canvas画布编辑功能&#xff0c;这是一项用途广泛的创新工具&#xff0c;专为需要高效创作文案的用户设计。 无论是职场人士、学生还是创作者&#xff0c;这项功能都能帮助快速生成、优化和编辑文案&#xff0c;提升效率的同时提高内容质量…

分布式事物XA、BASE、TCC、SAGA、AT

分布式事务——Seata 一、Seata的架构&#xff1a; 1、什么是Seata&#xff1a; 它是一款分布式事务解决方案。官网查看&#xff1a;Seata 2.执行过程 在分布式事务中&#xff0c;会有一个入口方法去调用各个微服务&#xff0c;每一个微服务都有一个分支事务&#xff0c;因…