UNet pytorch 胎教级介绍 使用DRIVE眼底血管分割数据集进行入门实战

news2024/10/16 20:21:50

同门的学妹做语义分割,于是打算稍微研究一下,最后的成果就是这篇文章,包括使用数据集进行测试,以及每一个部分的代码,还有一些思考改动和经验。
充分吸收本文知识你需要有pytorch的基础

U-net

U-Net:深度学习中的图像分割之星

当我们谈论图像处理中的深度学习,大多数人会立即想到卷积神经网络(CNN)和其在图像分类中的优异性能。但是,深度学习不仅仅可以进行图像分类,还有很多其他应用,其中之一就是图像分割。U-Net就是这一应用中的明星。

  • 什么是图像分割?

图像分割的目的是将图像分割成若干个有意义的部分,并对每一个部分进行标注。与图像分类不同的是,图像分类的目的是给整张图像一个标签,而图像分割要给图像中的每一个像素一个标签。

  • pytroch Unet复现
    接下来我们就要用pytorch来实现图像分割的效果,下面是Unet的官网网络结构模型,实际上数据变化维度不是很清晰,之后我们对其进行一下优化让我们看起来更明白,下面是原论文的图。
    在这里插入图片描述
    例如在与U的右侧拼接的时候他写的是copy(复制) and crop(裁剪) 数据维度具体是如何变小的裁剪有什么规则吗。这个问题我问了一下ChatGPT4,回答说是卷积让图片变小了,为了匹配尺寸,那这样裁剪不就损失信息了吗,572-570就少了两圈,这也不是减少参数量啊,好鸡肋。
    在这里插入图片描述
    还有为什么最后输出的图片为什么尺寸为什么不能等于原图,我们自己的数据集的标签大小和输入的图的大小似乎应该是一样的。如果大小不一致那预处理起来岂不是很不方便。
    总之ChatGPT的回答还是参数选择问题,可能还是由于深度学习的弱解释性,导致了当我们追问超参数时无法得到一个确切的答复,既然没有什么特殊意义,我们就开始改造成更容易理解的样子。
    在这里插入图片描述

所以凭借自己的理解我对这个图进行了一下改造改造成了易于理解的样子。
改动如下

  • 首先将原文中3×3的卷积核填充为0的卷积层改成1保证在经过该类卷积层的时候输出图片的大小不变
  • 第二发现在最后输出的时候原作者用了一个卷积核大小为1×1的卷积层,这也看不出来他有什么实际意义,也给他替换成3×3填充为1的,效果也没啥影响,不搞特立独行。

假设输入是一个3×512×512的图片输出也是3×512×512,中间每降一层样本点数量减半这样才符合我们实际的应用。
请添加图片描述

复现结果代码如下

import torch

class Conv(torch.nn.Module):
    def __init__(self,inchannel,outchannel):
        super(Conv, self).__init__()
        self.feature = torch.nn.Sequential(
            torch.nn.Conv2d(inchannel,outchannel,3,1,1),
            torch.nn.BatchNorm2d(outchannel),
            torch.nn.ReLU(),
            torch.nn.Conv2d(outchannel,outchannel,3,1,1),
            torch.nn.BatchNorm2d(outchannel),
            torch.nn.ReLU())
    def forward(self,x):
        return self.feature(x)


class UNet(torch.nn.Module):
    def __init__(self,inchannel,outchannel):
        super(UNet, self).__init__()
        self.conv1 = Conv(inchannel,64)
        self.conv2 = Conv(64,128)
        self.conv3 = Conv(128,256)
        self.conv4 = Conv(256,512)
        self.conv5 = Conv(512,1024)
        self.pool = torch.nn.MaxPool2d(2)

        self.up1 = torch.nn.ConvTranspose2d(1024,512,2,2)
        self.conv6 = Conv(1024,512)

        self.up2 = torch.nn.ConvTranspose2d(512,256,2,2)
        self.conv7 = Conv(512,256)

        self.up3 = torch.nn.ConvTranspose2d(256,128,2,2)
        self.conv8 = Conv(256,128)

        self.up4 = torch.nn.ConvTranspose2d(128,64,2,2)
        self.conv9 = Conv(128,64)

        self.conv10 = torch.nn.Conv2d(64,outchannel,3,1,1)

    def forward(self,x):
        xc1 = self.conv1(x)
        xp1 = self.pool(xc1)
        xc2 = self.conv2(xp1)
        xp2 = self.pool(xc2)
        xc3 = self.conv3(xp2)
        xp3 = self.pool(xc3)
        xc4 = self.conv4(xp3)
        xp4 = self.pool(xc4)
        xc5 = self.conv5(xp4)

        xu1 = self.up1(xc5)
        xm1 = torch.cat([xc4,xu1],dim=1)
        xc6 = self.conv6(xm1)

        xu2 = self.up2(xc6)
        xm2 = torch.cat([xc3,xu2],dim=1)
        xc7 = self.conv7(xm2)

        xu3 = self.up3(xc7)
        xm3 = torch.cat([xc2,xu3],dim=1)
        xc8 = self.conv8(xm3)

        xu4 = self.up4(xc8)
        xm4 = torch.cat([xc1,xu4],dim=1)
        xc9 = self.conv9(xm4)

        xc10 = self.conv10(xc9)

        return xc10




if __name__ == "__main__":

    input = torch.randn((1,3,512,512))
    # model = Conv(3,3)
    model = UNet(3,1)
    output = model(input)
    print(output.shape)

这段代码实现了一个基于 PyTorch 的 U-Net 神经网络架构代码分为两个主要部分,首先是 Conv 类,用于定义 U-Net 中的卷积块。然后是 UNet 类,用于构建整个 U-Net 网络。

这段代码展示了如何使用 PyTorch 构建 U-Net 神经网络架构,用于图像分割任务。U-Net 是一种经典的卷积神经网络结构,广泛应用于医学图像分割、图像处理等领域。

  1. Conv 类(卷积块):

    • Conv 类用于定义 U-Net 中的基本卷积块,它包含了两个卷积层、批归一化层和 ReLU 激活函数,用于特征提取。
    • __init__ 方法:初始化卷积块,接收输入通道数 inchannel 和输出通道数 outchannel,定义了一个包含多个卷积、批归一化和激活函数的序列。
    • forward 方法:实现卷积块的前向传播,接收输入数据 x,通过序列操作将输入数据传递并加工,最终返回加工后的特征。
  2. UNet 类(U-Net 网络):

    • UNet 类定义了 U-Net 网络的结构,它由编码器和解码器部分组成,用于实现图像分割。
    • __init__ 方法:初始化 U-Net 网络,接收输入通道数 inchannel 和输出通道数 outchannel(例如,用于生成分割掩码)。
    • 编码器部分:包括 conv1conv5,每个卷积块后跟一个最大池化层,用于逐渐减小图像尺寸和提取特征。
    • 解码器部分:通过反卷积层和卷积块进行特征上采样和融合,最终生成分割结果。
    • forward 方法:实现 U-Net 网络的前向传播,首先通过编码器提取特征,然后通过解码器生成分割结果。

if __name__ == "__main__": 部分,进行了以下操作:

  • 创建一个随机输入张量 input,形状为 (1, 3, 512, 512),表示一个批次大小为 1、通道数为 3、图像大小为 512x512 的输入图像。
  • 创建一个 U-Net 模型实例 model,传入输入通道数为 3(RGB 彩色图像通道数)和输出通道数为 1(用于生成分割掩码)。
  • 将输入张量传递给模型进行前向传播,生成输出张量 output
  • 打印输出张量的形状,用于检查网络输出的维度。

这里可能不太常见的就是这个层了torch.nn.ConvTranspose2dtorch.nn.ConvTranspose2d是PyTorch中用于实现二维转置卷积(反卷积)操作的类。它用于对输入数据进行上采样(增加分辨率)并生成更大尺寸的特征图。反卷积在图像分割、超分辨率重建等任务中经常被使用。
下面给一个简单的例子,反卷积和卷积层一样也有输出大小的对应公式。当我们设置反卷积的核大小为2步长为2时,可以将图片的宽高都增大二倍,实现一个上采样的过程OK了解到这其实就可以了,不影响复现。

import torch
import torch.nn as nn

# 定义输入数据,批次大小为1,通道数为3,高度和宽度为4
input_data = torch.randn(1, 3, 4, 4)

# 定义反卷积层
transposed_conv = nn.ConvTranspose2d(in_channels=3, out_channels=2, kernel_size=2, stride=2)

# 对输入数据进行反卷积操作
output_data = transposed_conv(input_data)

# 打印输出数据的形状
print("Input shape:", input_data.shape)
print("Output shape:", output_data.shape)

#Input shape: torch.Size([1, 3, 4, 4])
#Output shape: torch.Size([1, 2, 7, 7])

项目实战DRIVE血管语义分割

接下来我们使用Unet来分割一下DIRIVE数据集

DRIVE数据集介绍

先介绍一下DRIVE数据集
DRIVE数据集主要用于血管分割任务,其中的图像由用于血管定位的手动标记进行了标注。这个数据集的目的是促进与视网膜图像分析、血管分割和疾病诊断相关的计算机视觉算法的发展。

数据集下载之后,打开文件目录如下,这里我把trainning文件夹的名字换成了train
在这里插入图片描述
这里的文件夹分为三种一种是images保存的原来的图像

在这里插入图片描述
mask保存的是掩码标签
在这里插入图片描述
1st_manual 2nd_manual 里面保存的都是血管标签,我么要做的是血管分类任务。所以就是用Image文件夹里面的图像做训练数据,1st_manual里面的图片做标签

在这里插入图片描述

数据集读取

因为数据集里的标签和图片的格式是gif和tif所以不能用opencv直接读取,为了读取数据读取代码如下,文件命名为readpicture

from PIL import Image
import numpy as np
def read_picture(file_path):
    with Image.open(file_path) as img:
        return np.array(img)

if __name__ == "__main__":
    gif_path = r"DRIVE/train\images\21_training.tif" #改成自己的路径
    img = read_picture(gif_path)
    print(img.shape)

在这里插入图片描述

数据集构建代码

该代码需要在3.9以上的python环境下运行要不然会报错

import numpy as np
import os
from readpicture import read_picture
import cv2


for name in ['train','test']:
    picture_path = rf"DRIVE\{name}\images"
    label_path = fr"DRIVE\{name}\1st_manual"


    picturenames=os.listdir(picture_path)
    labelnames=os.listdir(label_path)

    data = []
    label = []


    for d,l in zip(picturenames,labelnames):
        dp = os.path.join(picture_path,d)
        lp = os.path.join(label_path,l)
        p =  cv2.resize(read_picture(dp),(512,512)).transpose(2,0,1)
        l = cv2.resize(read_picture(lp),(512,512)).reshape(1,512,512)
        p = (p - np.min(p)) / (np.max(p)-np.min(p))
        l = (l - np.min(l)) / (np.max(l)-np.min(l))
        data.append(p)
        label.append(l)



    dataset = np.array([i for i in zip(data,label)])

    # 改成自己的路径
    np.save(f"预处理好的数据集/{name}dataset",dataset)

运行好了之后会生成两个文件一个训练集一个测试集
在这里插入图片描述

模型训练

之后导入数据集和模型进行训练
首先分部分介绍代码然后给完整代码

  1. 首先导入必要的库
import numpy as np
import torch
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader, Dataset
from Unet import UNet
import copy
  1. 加载训练集和测试集
    路径改成自己的
traindata = np.load("预处理好的数据集/traindataset.npy", allow_pickle=True)
testdata = np.load("预处理好的数据集/testdataset.npy", allow_pickle=True)

  1. 自定义数据集类
class Dataset(Dataset):
    def __init__(self, data):
        self.len = len(data)
        self.x_data = torch.from_numpy(np.array(list(map(lambda x: x[0], data)), dtype=np.float32))
        self.y_data = torch.from_numpy(np.array(list(map(lambda x: x[1], data)))).float()

    def __getitem__(self, index):
        return self.x_data[index], self.y_data[index]

    def __len__(self):
        return self.len

  1. 创建数据集加载器
Train_dataset = Dataset(traindata)
Test_dataset = Dataset(testdata)
dataloader = DataLoader(Train_dataset, shuffle=True)
testloader = DataLoader(Test_dataset, shuffle=True)
  1. 初始化模型和设备选择
#设备是选择GPU还是CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#初始化模型输入通道数为3输出通道数为1
model = UNet(3,1)
#将模型迁移到GPU上
model.to(device)
  1. 定义训练函数和测试函数
#定义训练集损失列表最后画图用
train_loss = []
#定义训测试集损失列表最后画图用
test_loss = []
# 训练函数
def train():
    mloss = []
    for data in dataloader:
        datavalue, datalabel = data
        datavalue, datalabel = datavalue.to(device), datalabel.to(device)
        datalabel_pred = model(datavalue)
        loss = criterion(datalabel_pred, datalabel)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        mloss.append(loss.item())

    epoch_train_loss = torch.mean(torch.Tensor(mloss)).item()
    train_loss.append(epoch_train_loss)
    print("*"*10,epoch,"*"*10)
    print('训练集损失:', epoch_train_loss)
    test()


# 测试函数
def test():
    mloss = []
    with torch.no_grad():
        for testdata in testloader:
            testdatavalue, testdatalabel = testdata
            testdatavalue, testdatalabel = testdatavalue.to(device), testdatalabel.to(device)
            testdatalabel_pred = model(testdatavalue)
            loss = criterion(testdatalabel_pred, testdatalabel)
            mloss.append(loss.item())
        epoch_test_loss = torch.mean(torch.Tensor(mloss)).item()
        test_loss.append(epoch_test_loss)
        print('测试集损失',epoch_test_loss)

  1. 训练过程
bestmodel = None
bestepoch = None
bestloss = np.inf

for epoch in range(1, 101):
    train()
    if test_loss[epoch-1] < bestloss:
        bestloss = test_loss[epoch-1]
        bestepoch = epoch
        bestmodel = copy.deepcopy(model)

  1. 保存模型和绘制训练曲线
    路径改成自己的
torch.save(model, "训练好的模型权重/lastmodel.pt")
torch.save(bestmodel, "训练好的模型权重/bestmodel.pt")

plt.plot(train_loss)
plt.plot(test_loss)
plt.legend(['train', 'test'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

运行结果如下

在这里插入图片描述

训练完整代码

import numpy as np
import torch
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader, Dataset
from Unet import UNet
import copy

traindata = np.load("预处理好的数据集/traindataset.npy", allow_pickle=True)
testdata = np.load("预处理好的数据集/testdataset.npy", allow_pickle=True)

# 数据库加载
class Dataset(Dataset):
    def __init__(self, data):
        self.len = len(data)
        self.x_data = torch.from_numpy(np.array(list(map(lambda x: x[0], data)), dtype=np.float32))
        self.y_data = torch.from_numpy(np.array(list(map(lambda x: x[1], data)))).float()

    def __getitem__(self, index):
        return self.x_data[index], self.y_data[index]

    def __len__(self):
        return self.len



# 数据库dataloader
Train_dataset = Dataset(traindata)
Test_dataset = Dataset(testdata)
dataloader = DataLoader(Train_dataset, shuffle=True)
testloader = DataLoader(Test_dataset, shuffle=True)
# 训练设备选择GPU还是CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# 模型初始化
model = UNet(3,1)

model.to(device)

# 损失函数选择
# criterion = torch.nn.BCELoss()

criterion = torch.nn.MSELoss()
# criterion = torch.nn.CrossEntropyLoss()


criterion.to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01,momentum=0.9)


train_loss = []
test_loss = []
# 训练函数
def train():
    mloss = []
    for data in dataloader:
        datavalue, datalabel = data
        datavalue, datalabel = datavalue.to(device), datalabel.to(device)
        datalabel_pred = model(datavalue)
        loss = criterion(datalabel_pred, datalabel)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        mloss.append(loss.item())

    epoch_train_loss = torch.mean(torch.Tensor(mloss)).item()
    train_loss.append(epoch_train_loss)
    print("*"*10,epoch,"*"*10)
    print('训练集损失:', epoch_train_loss)
    test()


# 测试函数
def test():
    mloss = []
    with torch.no_grad():
        for testdata in testloader:
            testdatavalue, testdatalabel = testdata
            testdatavalue, testdatalabel = testdatavalue.to(device), testdatalabel.to(device)
            testdatalabel_pred = model(testdatavalue)
            loss = criterion(testdatalabel_pred, testdatalabel)
            mloss.append(loss.item())
        epoch_test_loss = torch.mean(torch.Tensor(mloss)).item()
        test_loss.append(epoch_test_loss)
        print('测试集损失',epoch_test_loss)



bestmodel = None
bestepoch = None
bestloss = np.inf


for epoch in range(1, 101):
    train()
    if test_loss[epoch-1] < bestloss:
        bestloss = test_loss[epoch-1]
        bestepoch = epoch
        bestmodel = copy.deepcopy(model)

print("最佳轮次为:{},最佳损失为:{}".format(bestepoch, bestloss))

torch.save(model, "训练好的模型权重/lastmodel.pt")
torch.save(bestmodel, "训练好的模型权重/bestmodel.pt")


plt.plot(train_loss)
plt.plot(test_loss)
plt.legend(['train','test'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

使用训练好的模型进行预测

import torch
import numpy as np
import cv2


dataset = np.load('预处理好的数据集/testdataset.npy', allow_pickle=True)


data = dataset[0][0]
label = dataset[0][1]

model = torch.load('训练好的模型权重/bestmodel.pt').cpu()
# model = torch.load('训练好的模型权重/lastmosel.pt').cpu()

output = model(torch.Tensor(data.reshape(1,3,data.shape[-2],data.shape[-1]))).detach().numpy()

cv2.imshow('label',label[0])
cv2.imshow('output',output[0][0])
cv2.waitKey()

运行结果如下,左侧标签,右侧预测结果
在这里插入图片描述
真实标签
在这里插入图片描述
预测结果

在这里插入图片描述
可以看到细节方面还是有些模糊的但是效果已经不错了

结束

总结在实验的过程中我发现这个Unet还是有一些玄学的东西下面就是我都一些经验总结

  • 数据必须进行归一化如果不进行归一化训练起来就会梯度爆炸
  • 图片大小必须为大于等于32的16的倍数,不然会报维度错误
  • 在pytorch的默认损失函数必须用MSE,用其他函数不是不收敛,就是重影或者灰蒙蒙一片
  • 训练的时候其实不管训练大小为多少样本比如你训练样本是224×224的其实他最后也能分割512*512的数据

如果你懒了不想找资料和复制的话,完整项目代码(包括数据集)请在公众号浩浩的科研笔记里购买
在这里插入图片描述

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

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

相关文章

您的密码是如何落入坏人之手的?

对于我们大多数人来说&#xff0c;密码只是无数在线服务最常用的身份验证方法。但对于网络犯罪分子而言&#xff0c;它的意义远不止于此——进入他人生活的捷径、至关重要的作案工具以及可以出售的商品。 对于我们大多数人来说&#xff0c;密码只是无数在线服务最常用的身份验证…

【MySql】数据库的聚合查询

写在最前面的话 哈喽&#xff0c;宝子们&#xff0c;今天给大家带来的是MySql数据库的聚合查询。在前面CRUD章节我们学习了表达式查询&#xff0c;表达式查询是针对列和列之间进行运算的&#xff0c;那么如果想在行和行之间进行运算&#xff0c;那么就需要用到聚合查询。聚合查…

计组+系统01:思维导图10分钟复习 I/O系统与中断

&#x1fa99;前言 考研笔记整理&#xff0c;纯复习向&#xff0c;思维导图基本就是全部内容了&#xff0c;不会涉及较深的知识点~~&#x1f95d;&#x1f95d; 第1版&#xff1a;查资料、画思维导图~&#x1f9e9;&#x1f9e9; 编辑&#xff1a; 梅头脑 BING AI 参考用书…

Deep Java Library(六)DJLServing自定义模型,自定义Translator注意事项

DJLServing自定义模型中自定义Translator注意事项需要仔细读一下DJLServing源码中的ServingTranslatorFactory类&#xff0c;&#xff0c;一开始不了解以为DJLServing选择Translator像玄学&#xff0c;后来看了像迷宫一样ServingTranslatorFactory类大致明白了&#xff0c;以下…

SAP-写了一个FUNCTION,用于读取订单中,指定工序的状态。

需求 在开发一个涉及工序的Report的过程中发现,SAP仅提供了Function去获取订单的状态,没有提供获取订单工序状态的Function。考虑到后续开发的过程中,还需要复用到这个功能,于是打算按这个需求去开发一个Function,传入AFVC表的主键,返回的是把该工序的全部已激活的状态,…

八 动手学深度学习v2 ——卷积神经网络之卷积+填充步幅+池化+LeNet

目录 1. 图像卷积总结2. 填充和步幅 padding和stride3. 多输入多输出通道4. 池化层5. LeNet 1. 图像卷积总结 二维卷积层的核心计算是二维互相关运算。最简单的形式是&#xff0c;对二维输入数据和卷积核执行互相关操作&#xff0c;然后添加一个偏置。核矩阵和偏移是可学习的参…

储能直流侧计量表DJSF1352

安科瑞 华楠 具有CE/UL/CPA/TUV认证 DJSF1352-RN导轨式直流电能表带有双路直流输入&#xff0c;主要针对电信基站、直流充电桩、太阳能光伏等应用场合而设计&#xff0c;该系列仪表可测量直流系统中的电压、电流、功率以及正反向电能等。在实际使用现场&#xff0c;即可计量总…

概念解析 | U-Net:医学图像分割的强大工具

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:U-Net。 U-Net:医学图像分割的强大工具 U-Net Architecture Explained - GeeksforGeeks 在医学图像分析的领域,一种称为U-Net的深度学习模型已经成为了一个标准工具。U-Net…

牛客练习赛115 A Mountain sequence

题目&#xff1a; 样例&#xff1a; 输入 3 5 1 2 3 4 5 3 3 3 3 3 1 2 1 输出 16 1 3 思路&#xff1a; 依据题意&#xff0c;再看数据范围&#xff0c;可以知道暴力肯定是不可能了&#xff0c;然后通过题目意思&#xff0c;我们可以排列模拟一下&#xff0c;这里排列所得结…

Decord库快速抽帧

Decord比Opencv块6倍&#xff01;&#xff01; 1. 使用教程 读取视频 # 1、读取使用 from decord import VideoReader from decord import cpu, gpuvr VideoReader(tiny-Kinetics-400\\abseiling\\_4YTwq0-73Y_000044_000054.mp4, ctxcpu(0))print(video frames:, len(vr)…

ArcGIS API for JavaScript 4.x 实现动态脉冲效果

1. 设计思路 主要通过定时刷新&#xff0c;每一次的脉冲渲染圈不停的放大&#xff0c;并且透明度缩小&#xff0c;直到达到一定的大小再退回0。 2. 实现代码 import MapView from "arcgis/core/views/MapView"; import GraphicsLayer from "arcgis/core/laye…

数学建模B多波束测线问题B

数学建模多波束测线问题 1.问题重述&#xff1a; 单波束测深是一种利用声波在水中传播的技术来测量水深的方法。它通过测量从船上发送声波到声波返回所用的时间来计算水深。然而&#xff0c;由于它是在单一点上连续测量的&#xff0c;因此数据在航迹上非常密集&#xff0c;但…

云备份——服务端客户端联合测试

一&#xff0c;准备工作 服务端清空备份文件信息、备份文件夹、压缩文件夹 客户端清空备份文件夹 二&#xff0c;开始测试 服务端配置文件 先启动服务端和客户端 向客户端指定文件夹放入稍微大点的文件&#xff0c;方便后续测试断点重传 2.1 上传功能测试 客户端自动上传成功…

【Altium Designer】AD20教程,实战,作图(一)

文章目录 完整制图方法1、建立一个完整的PCB工程&#xff0c;需要有sch文件、pcb文件、schlib文件、pcblib文件&#xff0c;后面两个不是必须的&#xff0c;后面两个用来自己创建库里面没有的东西。2、这个时候就可以画 原理图 ,这里我提一下库这个东西。3、画原理图4、编译原理…

系统架构设计师(第二版)学习笔记----计算机语言

【原文链接】系统架构设计师&#xff08;第二版&#xff09;学习笔记----计算机语言 文章目录 一、计算机语言的组成1.1 计算机语言的分类 二、机器语言2.1 机器语言指令信息2.2 机器语言指令格式的种类 三、汇编语言3.1 汇编语言中语句种类3.2 汇编语言指令和伪指令的语句格式…

数字孪生的深海迷航

上世纪70年代&#xff0c;美国宇航局&#xff08;NASA&#xff09;筹划构建复杂的大型载人航天器。当时科学家们发现&#xff0c;航天任务进行当中&#xff0c;航天器的维护和修理面临着环境复杂、危险性高、故障不易排查等问题。 与其“盲人摸象”式的找故障&#xff0c;不如干…

WRF DA环境需求、系统安装、调试与运行丨WRF DA变分资料同化、WRF DA混合同化新方法

目录 专题一 资料同化的基本理论与方法 专题二 WRF DA的环境需求、系统安装、调试与运行 专题三 观测资料与质量控制 专题四 WRF DA同化系统的配置、背景误差的构造 专题五 WRF DA变分资料同化、WRF DA混合同化新方法 专题六 变分同化的单点试验、混合同化的单点试验 专…

机器学习——Logistic Regression

0、前言&#xff1a; Logistic回归是解决分类问题的一种重要的机器学习算法模型 1、基本原理&#xff1a; Logistic Regression 首先是针对二分类任务提出的一种分类方法如果将概率看成一个数值属性&#xff0c;则二元分类问题的概率预测就可以转化为一个回归问题。这种思路最…

B Antiamuny wants to leaern binary search again

题目&#xff1a; C/C: int f(int l,int r,int x) { // l < x < rint cnt 0;while(l < r) {cnt;int mid (l r) / 2;if (mid x) break;if (mid < x) l mid 1;else r mid - 1;}return cnt; } 样例&#xff1a; 输入 5 3 7 2 6 12 2 2 10 3 6 14 8 5 8 1 输…

java实现调用百度地图

这里使用的springbootthymeleaf实现&#xff0c;所以需要有springboot技术使用起来更方便 当然&#xff0c;只使用html加js也可以实现&#xff0c;下面直接开始 首先我们需要去百度地图注册一个AK&#xff08;百度地图开放平台 | 百度地图API SDK | 地图开发&#xff09; 找到左…