基于PaddlePaddle搭建儿童X光胸部肺炎分类项目

该项目基于ResNet50网络对儿童胸片进行肺炎和正常二分类。先解压数据并生成训练、验证、测试列表,创建数据集并可视化。修改网络以获取最后卷积层输出用于类激活图。用Paddle高层API训练,评估得测试集准确率96.39%,并绘制混淆矩阵、ROC曲线(Normal AUC和Pneumonia AUC)及类激活图展示模型效果。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

基于paddlepaddle搭建儿童x光胸部肺炎分类项目 - 创想鸟

背景

这个项目是一个典型二分类任务,只是一个和医疗有关的项目。是基于resenet50网络进行分类。 这个项目增加训练完成后一些指标计算和展示,例如ACC,混淆矩阵,AUC,类激活图等(类激活图是参考大佬FutureSI的项目)

基于PaddlePaddle搭建儿童X光胸部肺炎分类项目 - 创想鸟

解压数据,生成数据列表

这个数据是一个公开数据,每张图片都是儿童的胸片。里面有两个类别一个是肺炎,一个正常的胸片。

In [ ]

!unzip -o data/data103760/data.zip -d /home/aistudio/work

In [80]

label = {'pneumonia_':1,'normal_':0}import osfrom PIL import Imageimport randomrandom.seed(2021)dataset_path = '/home/aistudio/work/data'trainf = open(os.path.join(dataset_path, 'train_list.txt'), 'w')valf = open(os.path.join(dataset_path, 'val_list.txt'), 'w')testf = open(os.path.join(dataset_path, 'test_list.txt'), 'w')for key,value in label.items():    img_dir = os.path.join(dataset_path, key)    imgs_name = os.listdir(img_dir)    random.shuffle(imgs_name)    for idx, name in enumerate(imgs_name):        img_path = os.path.join(img_dir, name)        if idx % 10 == 0:            valf.write((img_path + ' ' + str(value) + 'n'))        elif idx % 9 == 0:            testf.write((img_path + ' ' + str(value) + 'n'))        else:            trainf.write((img_path + ' ' + str(value) + 'n'))trainf.close()valf.close()testf.close()print('finished!')
finished!

创建Dataset 并可视化数据

In [81]

from paddle.vision.transforms import Compose,Transpose, BrightnessTransform,Resize,Normalize,RandomHorizontalFlip,RandomRotation,ContrastTransform,RandomCropfrom paddle.io import DataLoader, Datasetimport cv2import numpy as nptrain_transform = Compose([RandomRotation(degrees=10),#随机旋转0到10度                    RandomHorizontalFlip(),#随机翻转                    ContrastTransform(0.1),#随机调整图片的对比度                    BrightnessTransform(0.1),#随机调整图片的亮度                    Resize(size=(240,240)),#调整图片大小为240,240                    RandomCrop(size=(224,224)),#从240大小中随机裁剪出224                    Normalize(mean=[127.5, 127.5, 127.5],std=[127.5, 127.5, 127.5],data_format='HWC'),#归一化                    Transpose()])#对‘HWC’转换成‘CHW’val_transform = Compose([                    Resize(size=(224,224)),                    Normalize(mean=[127.5, 127.5, 127.5],std=[127.5, 127.5, 127.5],data_format='HWC'),                    Transpose()])# 定义DataSetclass XChestDateset(Dataset):    def __init__(self, txt_path, transform=None,mode='train'):        super(XChestDateset, self).__init__()        self.mode = mode        self.data_list = []        self.transform = transform        if mode == 'train':            self.data_list = np.loadtxt(txt_path, dtype='str')        elif mode == 'valid':            self.data_list = np.loadtxt(txt_path, dtype='str')        elif mode == 'test':            self.data_list = np.loadtxt(txt_path, dtype='str')    def __getitem__(self, idx):        img_path = self.data_list[idx][0]        img = cv2.imread(img_path)        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)        if self.transform:            img = self.transform(img)        return img, int(self.data_list[idx][1])    def __len__(self):        return self.data_list.shape[0]train_txt = 'work/data/train_list.txt'val_txt = 'work/data/val_list.txt'BATCH_SIZE = 16trn_dateset = XChestDateset(train_txt,train_transform, 'train')train_loader = DataLoader(trn_dateset, shuffle=True, batch_size=BATCH_SIZE  )val_dateset = XChestDateset(val_txt, val_transform,'valid')valid_loader = DataLoader(val_dateset, shuffle=False, batch_size=BATCH_SIZE)

In [82]

#可视化经过 数据增强后的胸片import matplotlib.pyplot as plt def imshow(img):    img = np.transpose(img, (1,2,0))    img = img*127.5 + 127.5  #反归一化,还原图片    img = img.astype(np.int32)    plt.imshow(img)dataiter = iter(train_loader)images, labels = dataiter.next()num = images.shape[0]row = 4fig = plt.figure(figsize=(14,14))for idx in range(num):    ax = fig.add_subplot(row,int(num/row), idx+1, xticks=[], yticks=[])    imshow(images[idx])    if labels[idx]:        ax.set_title('pneumonia')    else:        ax.set_title('normal')

创建RestNet50 网络

这个restNet50 网络代码是飞桨官方教程提供的代码

但是要最后生成类激活图就要稍微修改代码。

根据大佬FutureSI提到Grad-CAM 梯度加权的类激活热图原理中,需要获取网络最后一个卷积层输出的特征图,然后计算它的梯度。所以网络设计的时候需要提供一个方法,用来获取最后一个卷积层的输出

代码修改部分如下:

        """        以全局池化层为界,self.conv_layer用来存放所有卷积层。self.last_layer 用来全局池化层后面的全连接层        """        self.conv_layer = nn.Sequential(self.conv, self.pool2d_max,*self.bottleneck_block_list)        last_layer = [            paddle.nn.AdaptiveAvgPool2D(output_size=1),            nn.Flatten(1, -1),            nn.Linear(in_features=2048, out_features=class_dim),        ]        self.last_layer = nn.Sequential(*last_layer)        """        这是原来的代码,用以上的代码代替。其实就是单纯组合了一下,没有增加新的层        """        # 在c5的输出特征图上使用全局池化        # self.pool2d_avg = paddle.nn.AdaptiveAvgPool2D(output_size=1)        # 创建全连接层,输出大小为类别数目,经过残差网络的卷积和全局池化后,        # 卷积特征的维度是[B,2048,1,1],故最后一层全连接的输入维度是2048        # self.out = nn.Linear(in_features=2048, out_features=class_dim)    def forward(self, inputs):        # y = self.conv(inputs)        # y = self.pool2d_max(y)        # for bottleneck_block in self.bottleneck_block_list:        #     y = bottleneck_block(y)        # y = self.pool2d_avg(y)        # y = paddle.reshape(y, [y.shape[0], -1])        # y = self.out(y)        """        上面是原来的代码,用下面的两行代替(就是上面的代码组装起来而已。。。)        """        conv = self.conv_layer(inputs)        y = self.last_layer(conv)        return y

In [83]

# -*- coding:utf-8 -*-# ResNet模型代码import numpy as npimport paddleimport paddle.nn as nnimport paddle.nn.functional as F# ResNet中使用了BatchNorm层,在卷积层的后面加上BatchNorm以提升数值稳定性# 定义卷积批归一化块class ConvBNLayer(paddle.nn.Layer):    def __init__(self,                 num_channels,                 num_filters,                 filter_size,                 stride=1,                 groups=1,                 act=None):               """        num_channels, 卷积层的输入通道数        num_filters, 卷积层的输出通道数        stride, 卷积层的步幅        groups, 分组卷积的组数,默认groups=1不使用分组卷积        """        super(ConvBNLayer, self).__init__()        # 创建卷积层        self._conv = nn.Conv2D(            in_channels=num_channels,            out_channels=num_filters,            kernel_size=filter_size,            stride=stride,            padding=(filter_size - 1) // 2,            groups=groups,            bias_attr=False)        # 创建BatchNorm层        self._batch_norm = paddle.nn.BatchNorm2D(num_filters)                self.act = act    def forward(self, inputs):        y = self._conv(inputs)        y = self._batch_norm(y)        if self.act == 'leaky':            y = F.leaky_relu(x=y, negative_slope=0.1)        elif self.act == 'relu':            y = F.relu(x=y)        return y# 定义残差块# 每个残差块会对输入图片做三次卷积,然后跟输入图片进行短接# 如果残差块中第三次卷积输出特征图的形状与输入不一致,则对输入图片做1x1卷积,将其输出形状调整成一致class BottleneckBlock(paddle.nn.Layer):    def __init__(self,                 num_channels,                 num_filters,                 stride,                 shortcut=True):        super(BottleneckBlock, self).__init__()        # 创建第一个卷积层 1x1        self.conv0 = ConvBNLayer(            num_channels=num_channels,            num_filters=num_filters,            filter_size=1,            act='relu')        # 创建第二个卷积层 3x3        self.conv1 = ConvBNLayer(            num_channels=num_filters,            num_filters=num_filters,            filter_size=3,            stride=stride,            act='relu')        # 创建第三个卷积 1x1,但输出通道数乘以4        self.conv2 = ConvBNLayer(            num_channels=num_filters,            num_filters=num_filters * 4,            filter_size=1,            act=None)        # 如果conv2的输出跟此残差块的输入数据形状一致,则shortcut=True        # 否则shortcut = False,添加1个1x1的卷积作用在输入数据上,使其形状变成跟conv2一致        if not shortcut:            self.short = ConvBNLayer(                num_channels=num_channels,                num_filters=num_filters * 4,                filter_size=1,                stride=stride)        self.shortcut = shortcut        self._num_channels_out = num_filters * 4    def forward(self, inputs):        y = self.conv0(inputs)        conv1 = self.conv1(y)        conv2 = self.conv2(conv1)        # 如果shortcut=True,直接将inputs跟conv2的输出相加        # 否则需要对inputs进行一次卷积,将形状调整成跟conv2输出一致        if self.shortcut:            short = inputs        else:            short = self.short(inputs)        y = paddle.add(x=short, y=conv2)        y = F.relu(y)        return y# 定义ResNet模型class ResNet(paddle.nn.Layer):    def __init__(self, layers=50, class_dim=2):        """                layers, 网络层数,可以是50, 101或者152        class_dim,分类标签的类别数        """        super(ResNet, self).__init__()        self.layers = layers        supported_layers = [50, 101, 152]        assert layers in supported_layers,             "supported layers are {} but input layer is {}".format(supported_layers, layers)        if layers == 50:            #ResNet50包含多个模块,其中第2到第5个模块分别包含3、4、6、3个残差块            depth = [3, 4, 6, 3]        elif layers == 101:            #ResNet101包含多个模块,其中第2到第5个模块分别包含3、4、23、3个残差块            depth = [3, 4, 23, 3]        elif layers == 152:            #ResNet152包含多个模块,其中第2到第5个模块分别包含3、8、36、3个残差块            depth = [3, 8, 36, 3]                # 残差块中使用到的卷积的输出通道数        num_filters = [64, 128, 256, 512]        # ResNet的第一个模块,包含1个7x7卷积,后面跟着1个最大池化层        self.conv = ConvBNLayer(            num_channels=3,            num_filters=64,            filter_size=7,            stride=2,            act='relu')        self.pool2d_max = nn.MaxPool2D(            kernel_size=3,            stride=2,            padding=1)        # ResNet的第二到第五个模块c2、c3、c4、c5        self.bottleneck_block_list = []        num_channels = 64        for block in range(len(depth)):            shortcut = False            for i in range(depth[block]):                bottleneck_block = self.add_sublayer(                    'bb_%d_%d' % (block, i),                    BottleneckBlock(                        num_channels=num_channels,                        num_filters=num_filters[block],                        stride=2 if i == 0 and block != 0 else 1, # c3、c4、c5将会在第一个残差块使用stride=2;其余所有残差块stride=1                        shortcut=shortcut))                num_channels = bottleneck_block._num_channels_out                self.bottleneck_block_list.append(bottleneck_block)                shortcut = True        """        以全局池化层为界,self.conv_layer用来存放所有卷积层。self.last_layer 用来全局池化层后面的全连接层        """        self.conv_layer = nn.Sequential(self.conv, self.pool2d_max,*self.bottleneck_block_list)        last_layer = [            paddle.nn.AdaptiveAvgPool2D(output_size=1),            nn.Flatten(1, -1),            nn.Linear(in_features=2048, out_features=class_dim),        ]        self.last_layer = nn.Sequential(*last_layer)        """        这是原来的代码,用以上的代码代替。其实就是单纯组合了一下,没有增加新的层        """        # 在c5的输出特征图上使用全局池化        # self.pool2d_avg = paddle.nn.AdaptiveAvgPool2D(output_size=1)        # 创建全连接层,输出大小为类别数目,经过残差网络的卷积和全局池化后,        # 卷积特征的维度是[B,2048,1,1],故最后一层全连接的输入维度是2048        # self.out = nn.Linear(in_features=2048, out_features=class_dim)    def forward(self, inputs):        # y = self.conv(inputs)        # y = self.pool2d_max(y)        # for bottleneck_block in self.bottleneck_block_list:        #     y = bottleneck_block(y)        # y = self.pool2d_avg(y)        # y = paddle.reshape(y, [y.shape[0], -1])        # y = self.out(y)        """        上面是原来的代码,用下面的两行代替(就是上面的代码组装起来而已。。。)        """        conv = self.conv_layer(inputs)        y = self.last_layer(conv)        return y

使用Paddle 高层API 进行网络训练

In [84]

from paddle.regularizer import L2Decayfrom paddle.nn import CrossEntropyLossfrom paddle.metric import AccuracyBATCH_SIZE = 16 EPOCHS = 30 #训练次数decay_steps = int(len(trn_dateset)/BATCH_SIZE * EPOCHS)train_loader = DataLoader(trn_dateset, shuffle=True, batch_size=BATCH_SIZE  )valid_loader = DataLoader(val_dateset, shuffle=False, batch_size=BATCH_SIZE)model = paddle.Model(ResNet( class_dim=2))base_lr = 0.0125lr = paddle.optimizer.lr.PolynomialDecay(base_lr, power=0.9, decay_steps=decay_steps, end_lr=0.0)# 定义优化器optimizer = paddle.optimizer.Momentum(learning_rate=lr,                     momentum=0.9,                     weight_decay=L2Decay(1e-4),                     parameters=model.parameters())# 进行训练前准备model.prepare(optimizer, CrossEntropyLoss(), Accuracy(topk=(1, 5)))# 启动训练model.fit(train_loader,          valid_loader,          epochs=EPOCHS,          batch_size=BATCH_SIZE,          eval_freq =5,#多少epoch 进行验证          save_freq = 5,#多少epoch 进行模型保存          log_freq =30,#多少steps 打印训练信息          save_dir='/home/aistudio/checkpoint')

In [85]

#对验证集进行验证,查看验证集得分model.evaluate(valid_loader, log_freq=30, verbose=2)
Eval begin...step 30/32 - loss: 0.1032 - acc_top1: 0.9563 - acc_top5: 1.0000 - 64ms/stepstep 32/32 - loss: 0.8956 - acc_top1: 0.9559 - acc_top5: 1.0000 - 63ms/stepEval samples: 499
{'loss': [0.8956491], 'acc_top1': 0.9559118236472945, 'acc_top5': 1.0}

对测试集进行预测,计算准确率等指标并绘制混淆矩阵和ROC曲线

In [ ]

import cv2from PIL import Imageimport matplotlib.pyplot as pltimport numpy as npfrom sklearn.preprocessing import label_binarizeimport paddlefrom sklearn.metrics import accuracy_score,recall_score,precision_score,f1_score,confusion_matrixmodel_path = 'checkpoint/final.pdparams'model = ResNet( class_dim=2)para_state_dict = paddle.load(model_path)model.set_dict(para_state_dict)model.eval()test_txt = 'work/data/test_list.txt'test_dataset = XChestDateset(test_txt,val_transform, 'test')test_loader = DataLoader(test_dataset, shuffle=True, batch_size=1  )dataiter = iter(test_loader)y_score = list()pre_label = list()true_label = list()for images, labels in dataiter:    true_label.append(labels.numpy()[0])    out = model(images)    y_score.append(out.numpy()[0])    out = np.argmax(out.numpy())    pre_label.append(out)

In [ ]

#绘制混淆矩阵from sklearn.metrics import confusion_matrixfrom sklearn.metrics import classification_reportimport seaborn as snsconfusion = confusion_matrix(true_label, pre_label)#计算混淆矩阵plt.figure(figsize=(7,7))sns.heatmap(confusion,cmap='Blues_r',annot=True,fmt='.20g',annot_kws={'size':20,'weight':'bold', })#绘制混淆矩阵plt.xlabel('Predict')plt.ylabel('True')plt.show()print("混淆矩阵为:n{}".format(confusion))print("n计算各项指标:")print(classification_report(true_label, pre_label,digits=4))
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/seaborn/matrix.py:69: DeprecationWarning: `np.bool` is a deprecated alias for the builtin `bool`. To silence this warning, use `bool` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.bool_` here.Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations  mask = np.zeros(data.shape, np.bool)/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/seaborn/matrix.py:79: DeprecationWarning: `np.bool` is a deprecated alias for the builtin `bool`. To silence this warning, use `bool` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.bool_` here.Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations  dtype=np.bool)/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/colors.py:101: DeprecationWarning: np.asscalar(a) is deprecated since NumPy v1.16, use a.item() instead  ret = np.asscalar(ex)
混淆矩阵为:[[124  11] [  7 356]]计算各项指标:              precision    recall  f1-score   support           0     0.9466    0.9185    0.9323       135           1     0.9700    0.9807    0.9753       363    accuracy                         0.9639       498   macro avg     0.9583    0.9496    0.9538       498weighted avg     0.9637    0.9639    0.9637       498

In [ ]

#绘制ROC曲线from sklearn.metrics import roc_curve, roc_auc_score,aucplt.figure(figsize=(8,8))kind = {"normal":0,'pneumonia':1}y_score = np.array(y_score)fpr , tpr ,threshold = roc_curve(true_label, y_score[:,kind['normal']], pos_label=kind['normal'])roc_auc = auc(fpr,tpr) ###计算auc的fpr1 , tpr1 ,threshold = roc_curve(true_label, y_score[:,kind['pneumonia']], pos_label=kind['pneumonia'])roc_auc1 = auc(fpr1,tpr1) ###计算auc的plt.plot(fpr, tpr,marker='o', markersize=5,label='Normal')plt.plot(fpr1, tpr1,marker='*', markersize=5,label='Pneumonia')plt.title("Normal AUC:{:.4f}, Pneumonia AUC:{:.4f}".format(    roc_auc,roc_auc1))plt.xlabel('FPR')plt.ylabel('TPR')plt.legend(loc=4)plt.show()

绘制类激活图,可视化模型效果

In [86]

# 获取 Grad-CAM 类激活热图def get_gradcam(model, data, label, class_dim=2):    conv = model.conv_layer(data) # 得到模型最后一个卷积层的特征图    predict = model.last_layer(conv) # 得到前向计算的结果    label = paddle.reshape(label, [-1])    predict_one_hot = paddle.nn.functional.one_hot(label, class_dim) * predict # 将模型输出转化为one-hot向量    score = paddle.mean(predict_one_hot) # 得到预测结果中概率最高的那个分类的值    score.backward() # 反向传播计算梯度    grad_map = conv.grad # 得到目标类别的loss对最后一个卷积层输出的特征图的梯度    grad = paddle.mean(paddle.to_tensor(grad_map), (2, 3), keepdim=True) # 对特征图的梯度进行GAP(全局平局池化)    gradcam = paddle.sum(grad * conv, axis=1) # 将最后一个卷积层输出的特征图乘上从梯度求得权重进行各个通道的加和    gradcam = paddle.maximum(gradcam, paddle.to_tensor(0.)) # 进行ReLU操作,小于0的值设为0    for j in range(gradcam.shape[0]):        gradcam[j] = gradcam[j] / paddle.max(gradcam[j]) # 分别归一化至[0, 1]    return gradcam# 将 Grad-CAM 叠加在原图片上显示激活热图的效果def show_gradcam(model, data, label, class_dim=2, pic_size=224):    gradcams = get_gradcam(model, data, label,class_dim=class_dim)    for i in range(data.shape[0]):        img = (data[i].numpy() *127.5 +127.5).astype('uint8').transpose([1, 2, 0]) # 归一化至[0,255]区间,形状:[h,w,c]        heatmap = cv2.resize(gradcams[i].numpy() * 255., (data.shape[2], data.shape[3])).astype('uint8') # 调整热图尺寸与图片一致、归一化        heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) # 将热图转化为“伪彩热图”显示模式        superimposed_img = cv2.addWeighted(heatmap, .2, img, .8, 1.) # 将特图叠加到原图片上    return superimposed_imgmodel_path = 'checkpoint/final.pdparams'model = ResNet( class_dim=2)para_state_dict = paddle.load(model_path)model.set_dict(para_state_dict)model.eval()test_txt = 'work/data/test_list.txt'test_dataset = XChestDateset(test_txt,val_transform, 'test')test_loader = DataLoader(test_dataset, shuffle=True, batch_size=16  )dataiter = iter(test_loader)images, labels = dataiter.next()num = images.shape[0]row = 4fig = plt.figure(figsize=(14,14))for idx in range(num):    ax = fig.add_subplot(row,int(num/row), idx+1, xticks=[], yticks=[])    image = paddle.unsqueeze(images[idx], axis=0)    heat_map = show_gradcam(model, image, labels[idx], class_dim=2)    heat_map = cv2.cvtColor(heat_map, cv2.COLOR_BGR2RGB)    plt.imshow(heat_map)    if labels[idx]:        ax.set_title('pneumonia')    else:        ax.set_title('normal')
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/varbase_patch_methods.py:373: UserWarning: Warning:tensor.grad will return the tensor value of the gradient.   warnings.warn(warning_msg)

以上就是基于PaddlePaddle搭建儿童X光胸部肺炎分类项目的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/57986.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Tkinter应用程序中多页面切换的实现与管理
上一篇 2025年11月10日 07:22:54
文心一言网页版入口地址 文心一言官网账号注册教程
下一篇 2025年11月10日 07:22:58

相关推荐

  • 开源免费PHP工具 PHP开发效率提升利器

    推荐开源免费PHP开发工具以提升效率:VS Code、Sublime Text轻量高效,PhpStorm专业强大;调试用Xdebug、Kint、Ray;依赖管理选Composer;代码质量工具包括PHPStan、Psalm、PHP_CodeSniffer;数据库管理可用%ignore_a_1%MyA…

    2026年5月10日
    000
  • Matplotlib 地图中多类型图例的创建与优化

    Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化

    本教程旨在解决matplotlib地图可视化中,如何在一个图例中同时展示颜色块(如区域分类)和自定义标记(如特定兴趣点)的问题。文章详细介绍了当传统`patch`对象无法正确显示标记时,如何利用`matplotlib.lines.line2d`创建标记图例句柄,并将其与颜色块图例句柄合并,从而生成一…

    2026年5月10日 用户投稿
    100
  • Golang JSON序列化:控制敏感字段暴露的最佳实践

    本教程探讨golang中如何高效控制结构体字段在json序列化时的可见性。当需要将包含敏感信息的结构体数组转换为json响应时,通过利用`encoding/json`包提供的结构体标签,特别是`json:”-“`,可以轻松实现对特定字段的忽略,从而避免敏感数据泄露,确保api…

    2026年5月10日
    000
  • 利用海象运算符简化条件赋值:Python教程与最佳实践

    本文旨在探讨Python中海象运算符(:=)在条件赋值场景下的应用。通过对比传统if/else语句与海象运算符,以及条件表达式,分析海象运算符在简化代码、提高可读性方面的优势与局限性。并通过具体示例,展示如何在列表推导式等场景下合理使用海象运算符,同时强调其潜在的复杂性及替代方案,帮助开发者更好地掌…

    2026年5月10日
    100
  • 比特币新手教程 比特币交易平台有哪些

    比特币是一种去中心化的数字货币,基于区块链技术实现点对点交易,具有匿名性、有限发行和不可篡改等特点;新手可通过交易所购买,P2P交易获得比特币,常用平台包括Binance、OKX和Huobi;交易流程包括注册账户、实名认证、绑定支付方式、充值法币并下单购买,可选择市价单或限价单;比特币存储方式有交易…

    2026年5月10日
    000
  • c++中的SFINAE技术是什么_c++模板编程中的SFINAE原理与应用

    SFINAE 是“替换失败不是错误”的原则,指模板实例化时若参数替换导致错误,只要存在其他合法候选,编译器不报错而是继续重载决议。它用于条件启用模板、类型检测等场景,如通过 decltype 或 enable_if 控制函数重载,实现类型特征判断。尽管 C++20 引入 Concepts 简化了部分…

    2026年5月10日
    000
  • Go语言mgo查询构建:深入理解bson.M与日期范围查询的正确实践

    本文旨在解决go语言mgo库中构建复杂查询时,特别是涉及嵌套`bson.m`和日期范围筛选的常见错误。我们将深入剖析`bson.m`的类型特性,解释为何直接索引`interface{}`会导致“invalid operation”错误,并提供一种推荐的、结构清晰的代码重构方案,以确保查询条件能够正确…

    2026年5月10日
    100
  • RichHandler与Rich Progress集成:解决显示冲突的教程

    在使用rich库的`richhandler`进行日志输出并同时使用`progress`组件时,可能会遇到显示错乱或溢出问题。这通常是由于为`richhandler`和`progress`分别创建了独立的`console`实例导致的。解决方案是确保日志处理器和进度条组件共享同一个`console`实例…

    2026年5月10日
    000
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • 《魔兽世界》将于6月11日开启国服回归技术测试

    《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试

    《%ign%ignore_a_1%re_a_1%》官方宣布,将于6月11日开启国服回归技术测试,时间为7天,并称可以在6月内正式开服,玩家们可以访问官网下载战网客户端并预下载“巫妖王之怒”客户端,技术测试详情见下图。 WordAi WordAI是一个AI驱动的内容重写平台 53 查看详情 以上就是《…

    2026年5月10日 用户投稿
    200
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    100
  • 创建指定大小并填充特定数据的Golang文件教程

    本文将介绍如何使用Golang创建一个指定大小的文件,并用特定数据填充它。我们将使用 `os` 包提供的函数来创建和截断文件,从而实现快速生成大文件的目的。示例代码展示了如何创建一个10MB的文件,并将其填充为全零数据。掌握这些方法,可以方便地在例如日志系统或磁盘队列等场景中,预先创建测试文件或初始…

    2026年5月10日
    000
  • Python命令怎样使用profile分析脚本性能 Python命令性能分析的基础教程

    使用Python的cProfile模块分析脚本性能最直接的方式是通过命令行执行python -m cProfile your_script.py,它会输出每个函数的调用次数、总耗时、累积耗时等关键指标,帮助定位性能瓶颈;为进一步分析,可将结果保存为文件python -m cProfile -o ou…

    2026年5月10日
    000
  • 如何插入查询结果数据_SQL插入Select查询结果方法

    如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法如何插入查询结果数据_SQL插入Select查询结果方法

    使用INSERT INTO…SELECT语句可高效插入数据,通过NOT EXISTS、LEFT JOIN、MERGE语句或唯一约束避免重复;表结构不一致时可通过别名、类型转换、默认值或计算字段处理;结合存储过程可提升可维护性,支持参数化与动态SQL。 将查询结果数据插入到另一个表中,可以…

    2026年5月10日 用户投稿
    000
  • 使用 WebCodecs VideoDecoder 实现精确逐帧回退

    本文档旨在解决在使用 WebCodecs VideoDecoder 进行视频解码时,实现精确逐帧回退的问题。通过比较帧的时间戳与目标帧的时间戳,可以避免渲染中间帧,从而提高用户体验。本文将提供详细的解决方案和示例代码,帮助开发者实现精确的视频帧控制。 在使用 WebCodecs VideoDecod…

    2026年5月10日
    000
  • Discord.py 交互按钮超时与持久化解决方案

    本教程旨在解决Discord.py中交互按钮在一段时间后出现“This Interaction Failed”错误的问题。我们将深入探讨视图(View)的超时机制,并提供通过正确设置timeout参数以及利用bot.add_view()方法实现按钮持久化的具体方案,确保您的机器人交互功能稳定可靠,即…

    2026年5月10日
    000
  • Debian Copilot的社区活跃度如何

    debian copilot是codeberg社区维护的ai助手,旨在为debian用户提供服务。尽管搜索结果中没有直接提供关于debian copilot社区支持活跃度的具体数据,但我们可以通过debian社区的整体活跃度和特点来推断其活跃性。 Debian社区的一般情况: Debian拥有详尽的…

    2026年5月10日
    000
  • Python递归函数追踪与性能考量:以序列打印为例

    本文深入探讨了Python中一种递归打印序列元素的方法,并着重演示了如何通过引入缩进参数来有效追踪递归函数的执行流程和参数变化。通过实际代码示例,文章揭示了递归调用可能带来的潜在性能开销,特别是对调用栈空间的需求,以及Python默认递归深度限制可能导致的错误,为读者提供了理解和优化递归算法的实用见…

    2026年5月10日
    000
  • python中zip函数详解 python多序列压缩zip函数应用场景

    zip函数的应用场景包括:1) 同时遍历多个序列,2) 合并多个列表的数据,3) 数据分析和科学计算中的元素运算,4) 处理csv文件,5) 性能优化。zip函数是一个强大的工具,能够简化代码并提高处理多个序列时的效率。 在Python中,zip函数是一个非常有用的工具,它能够将多个可迭代对象打包成…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信