批量规范化与ResNet-paddle

批量规范化与ResNet——paddle部分

本文部分为paddle框架以及部分理论分析,torch框架对应代码可见批量规范化与ResNet

import paddle
print("paddle version:",paddle.__version__)
paddle version: 2.6.1

批量规范化

批量规范化(Batch Normalization,简称BN)是一种在深度学习中广泛使用的技术,旨在加速深层神经网络的训练过程,同时提高模型的稳定性和泛化能力。其基本原理是在网络训练过程中,对每个小批量(mini-batch)的数据进行标准化处理,使得每一层的输入数据具有固定的均值和方差。这样做可以有效缓解内部协变量偏移问题,即网络层之间输入数据分布的变化,从而帮助网络更容易学习和收敛。

具体来说,批量规范化的过程可以归纳为以下几个步骤:

  1. 计算均值和方差:在每次训练迭代中,对于当前小批量数据,首先计算其均值和方差。这两个统计量是基于当前小批量中的所有样本计算得到的。

  2. 标准化处理:接着,利用上一步计算得到的均值和方差,对当前小批量中的每个样本进行标准化处理,即减去均值并除以标准差,使得处理后的数据具有均值为0、方差为1的分布。为了数值稳定性,通常会在分母中加上一个小的常数ε(epsilon)。

  3. 引入可学习参数:标准化处理后的数据虽然具有固定的均值和方差,但其分布可能与网络的原始输入数据分布相差较大,这可能会限制网络的表示能力。因此,批量规范化还引入了两个可学习的参数:拉伸参数(scale,γ)和偏移参数(shift,β)。这两个参数分别用于对标准化后的数据进行缩放和偏移,以恢复其原始的数据分布特性。

  4. 训练过程中的调整:在训练过程中,批量规范化层会不断根据反向传播算法更新拉伸参数和偏移参数,同时也会更新网络中的其他参数。同时,为了能够在测试阶段使用批量规范化,通常会维护一组全局的均值和方差,这些全局统计量是在训练过程中通过滑动平均的方式计算得到的。

批量规范化的数学公式可以表示为:

BN ( x i ) = γ ( x i − μ B σ B 2 + ϵ ) + β \text{BN}(x_i) = \gamma \left( \frac{x_i - \mu_\mathcal{B}}{\sqrt{\sigma_\mathcal{B}^2 + \epsilon}} \right) + \beta BN(xi)=γ(σB2+ϵ xiμB)+β

其中, x i x_i xi表示当前小批量中的第 i i i个样本, μ B \mu_\mathcal{B} μB σ B 2 \sigma_\mathcal{B}^2 σB2分别表示当前小批量的均值和方差, γ \gamma γ β \beta β分别表示拉伸参数和偏移参数, ϵ \epsilon ϵ是一个小的常数用于数值稳定性。

# 让我们测试一下批量规范化层,它对一个mini-batch的输入进行规范化。
# 测试一下
batch_norm = paddle.nn.BatchNorm1D(5) # 创建一个批量规范化层,输入的维度为1维x1 = paddle.randn((3, 5))
y1 = batch_norm(x1) # 对输入进行批量规范化
print(y1) # 输出规范化后的结果
Tensor(shape=[3, 5], dtype=float32, place=Place(gpu:0), stop_gradient=False,[[ 1.37697136, -1.39297330,  1.33283722,  1.21341109,  1.39014637],[-0.96759880,  0.48505354, -0.25698468, -1.22396541, -0.91988957],[-0.40937260,  0.90791976, -1.07585251,  0.01055432, -0.47025684]])

观察数据可以发现,batch_norm(x1)的输出结果中,对于batch中的每个样本,其均值接近于0,方差接近于1,这符合批量规范化的预期效果。读者不妨思考,当batch_size为1时,批量规范化会如何工作?

运行后可以发现程序输入输出相同。这是因为当 batch_size为1时,批量规范化计算均值为每个数本身,方差则为0,因为此时没有足够的样本来计算这些统计量。因此,在训练是批量规范化通常要求batch_size大于1。同时,在测试时,批量规范化会使用训练过程中维护的全局均值和方差,因此不需要担心batch_size的问题。

接下来,我们再测试一下批量规范化层对一个mini-batch的输入进行规范化,其中batch_size为1。

x2 = paddle.randn((1, 5))
batch_norm.eval()
y2 = batch_norm(x2)
print(x2)
print(y2)
Tensor(shape=[1, 5], dtype=float32, place=Place(gpu:0), stop_gradient=True,[[ 0.05095419,  1.10956526,  0.29212147,  0.11223148, -0.45737460]])
Tensor(shape=[1, 5], dtype=float32, place=Place(gpu:0), stop_gradient=False,[[ 0.00438103,  1.10405421,  0.29548159,  0.12629299, -0.51910108]])

数据输出发现x2和y2一样,这是因为batch_norm还未参与训练,其全局均值和方差仍为0,因此测试时batch_norm(x2)的输出与x2相同。
让我们看一下批量规范化层对于图像数据的处理吧。

batch_norm = paddle.nn.BatchNorm2D(3) # 创建一个批量规范化层,输入的样本通道数为3x1 = paddle.randn((3, 3, 1, 2)) # 创建一个随机张量,维度为3x3x1x2
y1 = batch_norm(x1) # 对输入进行批量规范化
print(y1) # 输出规范化后的结果
Tensor(shape=[3, 3, 1, 2], dtype=float32, place=Place(gpu:0), stop_gradient=False,[[[[ 0.64140540,  0.73852235]],[[ 1.54244053,  0.14188576]],[[ 1.26155853,  0.40623882]]],[[[ 0.51346081, -1.84547091]],[[-0.50799036, -1.44020164]],[[-0.45918781, -0.83757848]]],[[[-0.85237151,  0.80445397]],[[-0.65344304,  0.91730863]],[[-1.46263731,  1.09160614]]]])/opt/conda/envs/python35-paddle120-env/lib/python3.10/site-packages/paddle/nn/layer/norm.py:824: UserWarning: When training, we now always track global mean and variance.warnings.warn(

可以发现,批量规范化层对于图像数据的处理与对于一维数据的处理类似,都是对每个通道进行规范化。对这些通道的“每个”输出执行批量规范化,每个通道都有自己的拉伸(scale)和偏移(shift)参数,这两个参数都是标量。 假设我们的小批量包含 m m m个样本,并且对于每个通道,卷积的输出具有高度 h h h和宽度 w w w。 那么对于卷积层,我们在每个输出通道的 m × h × w m \times h \times w m×h×w个元素上同时执行每个批量规范化。 因此,在计算平均值和方差时,我们会收集所有空间位置的值,然后在给定通道内应用相同的均值和方差,以便在每个空间位置对值进行规范化。

ResNet

ResNet(Residual Network)是一种深度卷积神经网络,它通过引入残差连接(Residual Connection)来解决深度神经网络中的梯度消失和梯度爆炸问题。ResNet的核心思想是让网络中的每一层都学习残差映射,而不是直接学习输出。残差映射是指输入与网络输出的差值,而不是直接学习输出。通过这种方式,网络可以更容易地学习到复杂的特征表示。

ResNet的残差连接结构如下所示:

在这里插入图片描述

其中, x x x表示输入, f ( x ) − x f(x)-x f(x)x表示残差映射, f ( x ) f(x) f(x)表示网络的实际输出。通过这种方式,网络可以更容易地学习到复杂的特征表示。

接下来,我们使用CIFAR-10来训练一个ResNet模型,看看模型效果吧!
CIFAR-10数据集是一个广泛使用的图像数据集,由Hinton的学生Alex Krizhevsky和Ilya Sutskever整理,用于识别普适物体的小型数据集。CIFAR-10数据集是从一个叫做“80 million tiny images dataset”(8000万张小图数据集)中精炼剥离出来的一部分,是该数据集的子集。由于原数据集涉及争议内容,目前已被下架。该数据集主要用于机器学习领域的计算机视觉算法基准测试,特别是在图像分类任务中。

  • 数据集内容
  • 图像数量:CIFAR-10数据集包含60,000张32x32像素的彩色(3通道)图像。
  • 类别分布:分为10个类别,每个类别包含6,000张图像。具体类别包括飞机(airplane)、汽车(automobile)、鸟类(bird)、猫(cat)、鹿(deer)、狗(dog)、蛙类(frog)、马(horse)、船(ship)和卡车(truck)。
  • 数据划分:数据集被划分为50,000张训练图片和10,000张测试图片。训练图片被进一步分为5个批次(batches),每个批次包含10,000张图片。

CIFAR-10数据集包含的是现实世界中真实的物体,与手写字符数据集(如MNIST)相比,CIFAR-10的噪声更大,物体的比例、特征都不尽相同,这为识别带来很大困难。直接的线性模型(如Softmax)在CIFAR-10上表现得很差,需要更复杂的模型来实现较高的分类准确率。CIFAR-10数据集是一个经典的图像分类数据集,广泛用于计算机视觉领域的研究和教育中。尽管其识别问题在深度学习模型的帮助下已经得到了较好的解决,但它仍然是初学者和研究者了解图像分类问题的一个良好起点。

import paddle  
from paddle.vision.transforms import Compose, Resize, ToTensor, Normalize  
from paddle.vision.datasets import Cifar10  
from paddle.io import DataLoader  # 定义数据预处理  
transform = Compose([  Resize((224, 224)),  ToTensor(),  Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  
])  # 加载数据集  
train_dataset = Cifar10(mode='train', transform=transform)  
test_dataset = Cifar10(mode='test', transform=transform)  # 创建数据加载器  
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)  
test_loader = DataLoader(test_dataset, batch_size=64)
item    80/41626 [..............................] - ETA: 43s - 1ms/itemCache file /home/aistudio/.cache/paddle/dataset/cifar/cifar-10-python.tar.gz not found, downloading https://dataset.bj.bcebos.com/cifar/cifar-10-python.tar.gz 
Begin to downloaditem 41626/41626 [============================>.] - ETA: 0s - 2ms/itemDownload finished

让我们将加载好的数据放入迭代器中,并看看训练集的前几张图片和标签。

# 查看训练集的前几张图片和标签
import math
import numpy as np  
import matplotlib.pyplot as plt  num_toshow = 10
for images, labels in train_loader:print(labels[0:num_toshow])  # 打印标签# 创建一个新的figure,尺寸为10x5英寸  plt.figure(figsize=(10, 5))  for i in range(num_toshow):  # 选择第i张图片  img = images[i]  # 将图片数据放缩到[0, 255]  data_min, data_max = paddle.min(img), paddle.max(img)img = (img - data_min) / (data_max - data_min)img = img * 255  # 将张量转换为numpy数组,并确保数据类型是uint8  img = img.numpy().astype(np.uint8)  # 将图片从CHW格式转换为HWC格式  img = img.transpose((1, 2, 0))  # 在subplot中展示图片  cols = round(math.sqrt(num_toshow))plt.subplot(cols, math.ceil(num_toshow / cols), i + 1)  plt.xticks([])  plt.yticks([])  plt.grid(False)  plt.imshow(img)  plt.xlabel(f'Image {i+1}')  # 展示所有subplot  plt.show()break
Tensor(shape=[10], dtype=int64, place=Place(gpu:0), stop_gradient=True,[0, 8, 6, 9, 7, 3, 8, 2, 3, 2])

在这里插入图片描述

接下来,让我们使用一个ResNet结构的网络模型,并使用CIFAR-10数据集进行训练。我们首先看一下PyTorch自带的resnet18模型。我们可以使用pytorch可视化工具netron查看YOLO网络模型结构。
在命令行执行:
C:\Users\admin>netron
Serving at http://localhost:8080
即可在网页端打开netron
将网络模型保存为.pt,或者将现有的.pt文件导入网页即可。如果没有安装netron,需要先pip一下~:pip install netron

from paddle.vision.models import resnet18  
import paddle.nn.functional as F  # 导入预训练的ResNet18模型  
model = resnet18(pretrained=True)  # 设置模型为评估模式  
model.eval()  # 保存模型  
paddle.save(model.state_dict(), 'data/resnet18.pdparams')
100%|██████████| 69183/69183 [00:01<00:00, 57674.41it/s]

在这里插入图片描述

对于ResNet结构,读者不妨参考原论文Deep Residual Learning for Image Recognition中的介绍。如下图所示,对于一个没有残差结构的普通卷积神经网络,当网络层数更多时,网络训练和测试反而会变得更差,这是由于梯度消失和梯度爆炸问题导致的。

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

然而当采用残差结构时,网络训练和测试的效果会随层数增加而提升。如下图所示,下图使用了CIFAR-10数据集进行了验证。
在这里插入图片描述

接下来让我们来训练测试一下ResNet18模型。首先我们看一下模型输入输出尺寸是否正确。

out = model(images)
print(out.shape)
[64, 1000]

可以看到,原网络输出类别个数为1000,我们需要对其进行结构修改。

import paddle.nn as nn  class ResNet18_CIFAR_10(nn.Layer):  def __init__(self, output_size=10):  super(ResNet18_CIFAR_10, self).__init__()  # 定义ResNet18模型并加载预训练权重  self.resnet18 = resnet18(pretrained=True)  # 修改全连接层输出类别个数  num_ftrs = self.resnet18.fc.weight.shape[0]  self.resnet18.fc = nn.Linear(num_ftrs, output_size)  def forward(self, x):  # 前向传播  x = self.resnet18(x)  return x  
net = ResNet18_CIFAR_10()
out = net(images)
print(out.shape)
[64, 10]

接下来我们进行训练和测试。

from paddle.vision.transforms import Compose, Normalize  
import warnings  
warnings.filterwarnings('ignore')  # 忽略所有警告# 设置设备  
device = paddle.set_device('gpu' if paddle.is_compiled_with_cuda() else 'cpu')  
net = net.to(device)  # 损失函数和优化器  
criterion = paddle.nn.CrossEntropyLoss()  
optimizer = paddle.optimizer.Adam(parameters=net.parameters(), learning_rate=0.001)  num_epochs = 10  
for epoch in range(num_epochs):  for i, (images, labels) in enumerate(train_loader):  images = images.to(device)  labels = labels.to(device)  outputs = net(images)  loss = criterion(outputs, labels)  loss.backward()  optimizer.step()  optimizer.clear_grad()  if (i + 1) % 100 == 0:  print(f'Epoch [{epoch + 1}/{num_epochs}], Step [{i + 1}/{len(train_loader)}], Loss: {loss.numpy():.4f}')
Epoch [10/10], Step [700/782], Loss: 0.0456

接下来我们在测试集上对模型进行测试。

# 测试模型
net.eval() 
total = 0  
correct = 0  
for imgs, labels in test_loader():  outputs = net(imgs)  _, predicted = paddle.topk(outputs, k=1, axis=1)  total += labels.shape[0]  correct += paddle.sum(paddle.equal(predicted.reshape((1,-1)), labels)).numpy()  breakprint('Accuracy: %.2f %%' % (100 * correct / total))
Accuracy: 85.94 %

可以看到模型在测试集上具有较好的准确率。ResNet在工程上主要有以下应用领域:

  1. 图像分类

    • ResNet在图像分类任务中表现优异,尤其是在大规模数据集(如ImageNet)上取得了卓越的性能。通过在大规模数据集上进行预训练,ResNet可以学习到强大的特征表示,进而在各种图像分类任务中取得良好的结果。
  2. 目标检测

    • 在目标检测任务中,ResNet常作为骨干网络(backbone network),结合相应的检测框架(如Faster R-CNN、YOLO、SSD等)构建高性能的目标检测系统。这些系统能够准确识别图像中的目标物体,并给出其位置和类别信息。
  3. 语义分割

    • 语义分割是计算机视觉领域的一个重要任务,旨在将图像中的每个像素划分为相应的类别。ResNet在语义分割任务中也具有广泛应用,通过与全卷积网络(FCN)等结构相结合,实现对图像像素级别的精细分类。

除了计算机视觉领域,ResNet还逐渐渗透到自然语言处理、语音识别等其他领域。例如,在自然语言处理中,ResNet可用于文本分类、情感分析等任务;在语音识别中,ResNet可用于提取音频特征,提高识别率。ResNet作为一种强大的深度学习模型结构,在多个领域取得了显著成果,并展现出广阔的发展前景。未来,随着技术的不断进步和应用场景的不断拓展,ResNet有望在更多领域发挥更大作用,为人类社会的进步贡献更多力量。
,ResNet常作为骨干网络(backbone network),结合相应的检测框架(如Faster R-CNN、YOLO、SSD等)构建高性能的目标检测系统。这些系统能够准确识别图像中的目标物体,并给出其位置和类别信息。

  1. 语义分割
    • 语义分割是计算机视觉领域的一个重要任务,旨在将图像中的每个像素划分为相应的类别。ResNet在语义分割任务中也具有广泛应用,通过与全卷积网络(FCN)等结构相结合,实现对图像像素级别的精细分类。

除了计算机视觉领域,ResNet还逐渐渗透到自然语言处理、语音识别等其他领域。例如,在自然语言处理中,ResNet可用于文本分类、情感分析等任务;在语音识别中,ResNet可用于提取音频特征,提高识别率。ResNet作为一种强大的深度学习模型结构,在多个领域取得了显著成果,并展现出广阔的发展前景。未来,随着技术的不断进步和应用场景的不断拓展,ResNet有望在更多领域发挥更大作用,为人类社会的进步贡献更多力量。

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

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

相关文章

从零开始快速构建Vue3项目

一、技术选型 组件大类 具体插件 vue3插件 相关插件开发文档 基础架构搭建 初始项目搭建、打包构件工具&#xff1a;vite开始 | Vite路由管理及菜单权限封装vue-router介绍 | Vue Router状态管理Pinia介绍 | Pinia 中文文档API请求及异常封装axiosUI框架 element-uihttps…

74HC245

74HC245&#xff1a;典型的CMOS型缓冲门电路 在这里用于增加电压

BFS 算法专题(三):BFS 解决边权为 1 的最短路问题

目录 1. 迷宫中离入口最近的出口 1.1 算法原理 1.2 算法代码 2. 最小基因变化 ★★★ 2.1 算法原理 2.2 算法代码 3. 单词接龙 3.1 算法原理 3.2 算法代码 4. 为高尔夫比赛砍树 (hard) 4.1 算法原理 4.2 算法代码 1. 迷宫中离入口最近的出口 . - 力扣&#xff08;…

「数据要素」行业简报|2024.11.上刊

纵观数据要素行业动态&#xff0c;洞察行业风向&#xff0c;把握行业脉搏&#xff01; 一、政策发布 1、《山东省公共数据资源登记管理工作规范(试行)》公开征求意见 11月7日&#xff0c;为认真贯彻落实《中共中央办公厅 国务院办公厅关于加快公共数据资源开发利用的意见》《…

有什么好用的 WebSocket 调试工具吗?

在开发和测试 WebSocket 应用程序时&#xff0c;确保客户端能够正确地与服务器建立连接、发送和接收消息是非常重要的。 市面上有许多通用的 API 测试工具&#xff0c;它们大多专注于 HTTP 请求&#xff0c;而对于 WebSocket 的支持则显得较为有限。这种局限性使得开发者在寻找…

MQTT协议解析 : 物联网领域的最佳选择

1. MQTT协议概述 1.1 MQTT协议是什么 MQTT : Message Queuing Telemetry Transport 模式 : 发布 / 订阅主题优点 : 代码量小、低带宽、实时可靠应用 : 物联网、小型设备、移动应用MQTT 常用端口 : 1883 MQTT是一个网络协议&#xff0c;和HTTP类似&#xff0c;因为轻量简单&…

鸿蒙HarmonyOS 网络请求获取数据Http

注意的是;要为接口返回值指定类型 &#xff0c;以及定义接口数据类型 index.ets import { http } from kit.NetworkKit;interface createAtType {date: number,}interface dataListType {createAt: createAtType;imgUrl: }Component export default struct TabBar {State dat…

2024136读书笔记|《飞鸟集》——使生如夏花之绚烂,死如秋叶之静美

2024136读书笔记|《飞鸟集》——使生如夏花之绚烂&#xff0c;死如秋叶之静美 《飞鸟集》[印]泰戈尔&#xff0c;一本有意思的诗集&#xff0c;中英文对照着读更有意思。“你是谁&#xff0c;读者&#xff0c;百年后读着我的诗&#xff1f;”让我觉得有些久别重逢&#xff0c;忽…

ROS Action

在 ROS 中&#xff0c;Action 是一种支持长时间异步任务的通信机制。与 Service 不同&#xff0c;Action 允许客户端发起一个请求&#xff0c;并在任务执行的过程中不断接收反馈&#xff0c;直到任务完成。这种机制非常适用于可能需要较长时间来完成的任务&#xff0c;比如机器…

约束(MYSQL)

not null&#xff08;非空&#xff09; unique&#xff08;唯一&#xff09; default&#xff08;默认约束&#xff0c;规定值&#xff09; 主键约束primary key&#xff08;非空且唯一&#xff09; auto_increment&#xff08;自增类型&#xff09; 复合主键 check&#xff08…

笔记 | image may have poor performance,or fail,if run via emulation

在Docker Desktop中现象如图&#xff1a; 当你运行 AMD64 平台代码时&#xff08;Intel 和 AMD 芯&#xff09;&#xff0c;你的 Mac 必须模拟其CPU架构&#xff08;因为你自身是ARM&#xff09;。这通常会非常吃性能。 Docker Desktop 警告你在模拟 Intel/AMD x64 CPU 时性能可…

【C++】C++11特性(上)

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;C 个人主页&#xff1a;Celias blog~ 目录 一、列表初始化 二、std::initializer_list 三、右值引用和移…

24/11/7 算法笔记 PCA主成分分析

假如我们的数据集是n维的&#xff0c;共有m个数据(x,x,...,x)。我们希望将这m个数据的维度从n维降到k维&#xff0c;希望这m个k维的数据集尽可能的代表原始数据集。我们知道数据从n维降到k维肯定会有损失&#xff0c;但是我们希望损失尽可能的小。那么如何让这k维的数据尽可能表…

JS 实现SSE通讯和了解SSE通讯

SSE 介绍&#xff1a; Server-Sent Events&#xff08;SSE&#xff09;是一种用于实现服务器向客户端实时推送数据的Web技术。与传统的轮询和长轮询相比&#xff0c;SSE提供了更高效和实时的数据推送机制。 SSE基于HTTP协议&#xff0c;允许服务器将数据以事件流&#xff08;…

C/C++每日一练:查找链表的中间节点

链表&#xff08;Linked List&#xff09; 链表是一种线性数据结构&#xff0c;由一系列节点&#xff08;Node&#xff09;通过指针链接在一起。与数组不同&#xff0c;链表中的元素在内存中不需要连续存储&#xff0c;每个节点包含两部分&#xff1a; 数据部分&#xff1a;存…

对称加密与非对称加密:密码学的基石及 RSA 算法详解

对称加密与非对称加密&#xff1a;密码学的基石及 RSA 算法详解 在当今数字化的时代&#xff0c;信息安全至关重要。对称加密和非对称加密作为密码学中的两种基本加密技术&#xff0c;为我们的数据安全提供了强大的保障。本文将深入探讨对称加密和非对称加密的特点、应用场景&…

PH47代码框架全局函数及功能类

PH47代码框架全局函数及功能类 概述 全局函数及功能类体系是PH47框架当中除了4个逻辑层之外最重要的组成部分之一&#xff0c;它们可以在 整个PH7 代码框架及用户代码中使用。常用全局函数及功能类为 PH7 代码框架提供了最常用和最基础的功能实现。 全局函数主要包含了对时间…

力扣 LeetCode 203. 移除链表元素(Day2:链表)

解题思路&#xff1a; 方法一&#xff1a;头节点和非头节点分开处理 方法二&#xff1a;定义一个dummy虚拟节点&#xff0c;后面的节点就可以采用相同的处理方式 注意&#xff1a; cur需要指向要删除的节点的上一个节点&#xff0c;因为要越过这一个被删除的节点 class Sol…

IEC60870-5-104 协议源码架构详细分析

IEC60870-5-104 协议源码架构 前言一、资源三、目录层级一二、目录层级二config/lib60870_config.hdependencies/READMEexamplesCMakeLists.txtcs101_master_balancedcs104_client_asyncmulti_client_servertls_clienttls_server说明 make这些文件的作用是否需要导入这些文件&a…

turbo c 2.0 画螺栓

代码; #include<graphics.h> void bolt(x0,y0,d,l) int x0,y0,d,l; {int x1,x2,x3,x4,x5,x6,x7,x8;int y1,y2,y3,y4,y5,r1,r2,b,c;if(l>2*d) b2*d;else b1;r11.5*d;r20.38*d;c0.1*d;x1x0-0.7*d;x2x0-0.61*d;x3x0-0.32*d;x4x00.8*d;x5x0l-b;x6x0l-c;x7x0l-0.05*d;x8x0…