整理一下看到的自定义数据读取的方法,较好的有一下三篇文章, 其实自定义的方法就是把现有数据集的train和test分别用 含有图像路径与label的list返回就好了,所以需要根据数据集随机应变。

所有图片都在一个文件夹1

之前刚开始用的时候,写Dataloader遇到不少坑。网上有一些教程 分为all images in one folder 和 each class one folder。后面的那种写的人比较多,我写一下前面的这种,程式化的东西,每次不同的任务改几个参数就好。

等训练的时候写一篇文章把2333


一.已有的东西

举例子:用kaggle上的一个dog breed的数据集为例。数据文件夹里面有三个子目录

test: 几千张图片,没有标签,测试集

train: 10222张狗的图片,全是jpg,大小不一,有长有宽,基本都在400×300以上

labels.csv : excel表格, 图片名称+品种名称

<img src="https://pic4.zhimg.com/v2-6128d817c09f05fe3bdfe05e1f84a92f_b.jpg" data-caption="" data-size="normal" data-rawwidth="496" data-rawheight="85" class="origin_image zh-lightbox-thumb" width="496" data-original="https://pic4.zhimg.com/v2-6128d817c09f05fe3bdfe05e1f84a92f_r.jpg">

我喜欢先用pandas把表格信息读出来看一看

import pandas as pd
import numpy as np
df = pd.read_csv('./dog_breed/labels.csv')
print(df.info())
print(df.head())

<img src="https://pic1.zhimg.com/v2-9d680235e5ff00c3f869a3eab4630ca4_b.jpg" data-caption="" data-size="normal" data-rawwidth="731" data-rawheight="265" class="origin_image zh-lightbox-thumb" width="731" data-original="https://pic1.zhimg.com/v2-9d680235e5ff00c3f869a3eab4630ca4_r.jpg">

看到,一共有10222个数据,id对应的是图片的名字,但是没有后缀 .jpg。 breed对应的是犬种。


二.预处理

我们要做的事情是:

1)得到一个长 list1 : 里面是每张图片的路径

2)另外一个长list2: 里面是每张图片对应的标签(整数),顺序要和list1对应。

3)把这两个list切分出来一部分作为验证集

1)看看一共多少个breed,把每种breed名称和一个数字编号对应起来:

from pandas import Series,DataFramebreed = df['breed']
breed_np = Series.as_matrix(breed)
print(type(breed_np) )
print(breed_np.shape)   #(10222,)#看一下一共多少不同种类
breed_set = set(breed_np)
print(len(breed_set))   #120#构建一个编号与名称对应的字典,以后输出的数字要变成名字的时候用:
breed_120_list = list(breed_set)
dic = {}
for i in range(120):dic[  breed_120_list[i]   ] = i

2)处理id那一列,分割成两段:

file =  Series.as_matrix(df["id"])
print(file.shape)import os
file = [i+".jpg" for i in file]
file = [os.path.join("./dog_breed/train",i) for i in file ]
file_train = file[:8000]
file_test = file[8000:]
print(file_train)np.save( "file_train.npy" ,file_train )
np.save( "file_test.npy" ,file_test )

里面就是图片的路径了

<img src="https://pic3.zhimg.com/v2-b740e480301df1fded91c92090065736_b.jpg" data-caption="" data-size="normal" data-rawwidth="1076" data-rawheight="113" class="origin_image zh-lightbox-thumb" width="1076" data-original="https://pic3.zhimg.com/v2-b740e480301df1fded91c92090065736_r.jpg">

3)处理breed那一列,分成两段:

breed = Series.as_matrix(df["breed"])
print(breed.shape)
number = []
for i in range(10222):number.append(  dic[ breed[i] ]  )
number = np.array(number)
number_train = number[:8000]
number_test = number[8000:]
np.save( "number_train.npy" ,number_train )
np.save( "number_test.npy" ,number_test )


三.Dataloader

我们已经有了图片路径的list,target编号的list。填到Dataset类里面就行了。

from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utilsnormalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]
)
preprocess = transforms.Compose([#transforms.Scale(256),#transforms.CenterCrop(224),transforms.ToTensor(),normalize
])def default_loader(path):img_pil =  Image.open(path)img_pil = img_pil.resize((224,224))img_tensor = preprocess(img_pil)return img_tensor#当然出来的时候已经全都变成了tensor
class trainset(Dataset):def __init__(self, loader=default_loader):#定义好 image 的路径self.images = file_trainself.target = number_trainself.loader = loaderdef __getitem__(self, index):fn = self.images[index]img = self.loader(fn)target = self.target[index]return img,targetdef __len__(self):return len(self.images)

我们看一下代码,自定义Dataset只需要最下面一个class,继承自Dataset类。有三个私有函数

def __init__(self, loader=default_loader):

这个里面一般要初始化一个loader(代码见上面),一个images_path的列表,一个target的列表

def __getitem__(self, index):

这里吗就是在给你一个index的时候,你返回一个图片的tensor和target的tensor,使用了loader方法,经过 归一化,剪裁,类型转化,从图像变成tensor

def __len__(self):

return你所有数据的个数

这三个综合起来看呢,其实就是你告诉它你所有数据的长度,它每次给你返回一个shuffle过的index,以这个方式遍历数据集,通过 __getitem__(self, index)返回一组你要的(input,target)


四.使用

实例化一个dataset,然后用Dataloader 包起来

train_data  = trainset()
trainloader = DataLoader(train_data, batch_size=4,shuffle=True)

<img src="https://pic1.zhimg.com/v2-8bbf753ce61d9a2cf0082b003b67d03c_b.jpg" data-caption="" data-size="normal" data-rawwidth="615" data-rawheight="181" class="origin_image zh-lightbox-thumb" width="615" data-original="https://pic1.zhimg.com/v2-8bbf753ce61d9a2cf0082b003b67d03c_r.jpg">

所有图片都在一个文件夹2

在上一篇博客PyTorch学习之路(level1)——训练一个图像分类模型中介绍了如何用PyTorch训练一个图像分类模型,建议先看懂那篇博客后再看这篇博客。在那份代码中,采用torchvision.datasets.ImageFolder这个接口来读取图像数据,该接口默认你的训练数据是按照一个类别存放在一个文件夹下。但是有些情况下你的图像数据不是这样维护的,比如一个文件夹下面各个类别的图像数据都有,同时用一个对应的标签文件,比如txt文件来维护图像和标签的对应关系,在这种情况下就不能用torchvision.datasets.ImageFolder来读取数据了,需要自定义一个数据读取接口。另外这篇博客最后还顺带介绍如何保存模型和多GPU训练。

怎么做呢?

先来看看torchvision.datasets.ImageFolder这个类是怎么写的,主要代码如下,想详细了解的可以看:官方github代码。

看起来很复杂,其实非常简单。继承的类是torch.utils.data.Dataset,主要包含三个方法:初始化__init__,获取图像__getitem__,数据集数量 __len____init__方法中先通过find_classes函数得到分类的类别名(classes)和类别名与数字类别的映射关系字典(class_to_idx)。然后通过make_dataset函数得到imags,这个imags是一个列表,其中每个值是一个tuple,每个tuple包含两个元素:图像路径和标签。剩下的就是一些赋值操作了。在__getitem__方法中最重要的就是 img = self.loader(path)这行,表示数据读取,可以从__init__方法中看出self.loader采用的是default_loader,这个default_loader的核心就是用python的PIL库的Image模块来读取图像数据。

class ImageFolder(data.Dataset):"""A generic data loader where the images are arranged in this way: ::root/dog/xxx.pngroot/dog/xxy.pngroot/dog/xxz.pngroot/cat/123.pngroot/cat/nsdf3.pngroot/cat/asd932_.pngArgs:root (string): Root directory path.transform (callable, optional): A function/transform that  takes in an PIL imageand returns a transformed version. E.g, ``transforms.RandomCrop``target_transform (callable, optional): A function/transform that takes in thetarget and transforms it.loader (callable, optional): A function to load an image given its path.Attributes:classes (list): List of the class names.class_to_idx (dict): Dict with items (class_name, class_index).imgs (list): List of (image path, class_index) tuples"""def __init__(self, root, transform=None, target_transform=None,loader=default_loader):classes, class_to_idx = find_classes(root)imgs = make_dataset(root, class_to_idx)if len(imgs) == 0:raise(RuntimeError("Found 0 images in subfolders of: " + root + "\n""Supported image extensions are: " + ",".join(IMG_EXTENSIONS)))self.root = rootself.imgs = imgsself.classes = classesself.class_to_idx = class_to_idxself.transform = transformself.target_transform = target_transformself.loader = loaderdef __getitem__(self, index):"""Args:index (int): IndexReturns:tuple: (image, target) where target is class_index of the target class."""path, target = self.imgs[index]img = self.loader(path)if self.transform is not None:img = self.transform(img)if self.target_transform is not None:target = self.target_transform(target)return img, targetdef __len__(self):return len(self.imgs)

稍微看下default_loader函数,该函数主要分两种情况调用两个函数,一般采用pil_loader函数。

def pil_loader(path):with open(path, 'rb') as f:with Image.open(f) as img:return img.convert('RGB')def accimage_loader(path):import accimagetry:return accimage.Image(path)except IOError:# Potentially a decoding problem, fall back to PIL.Imagereturn pil_loader(path)def default_loader(path):from torchvision import get_image_backendif get_image_backend() == 'accimage':return accimage_loader(path)else:return pil_loader(path)

看懂了ImageFolder这个类,就可以自定义一个你自己的数据读取接口了。

首先在PyTorch中和数据读取相关的类基本都要继承一个基类:torch.utils.data.Dataset。然后再改写其中的__init____len____getitem__等方法即可

下面假设img_path是你的图像文件夹,该文件夹下面放了所有图像数据(包括训练和测试),然后txt_path下面放了train.txt和val.txt两个文件,txt文件中每行都是图像路径,tab键,标签。所以下面代码的__init__方法中self.img_name和self.img_label的读取方式就跟你数据的存放方式有关,你可以根据你实际数据的维护方式做调整。__getitem__方法没有做太大改动,依然采用default_loader方法来读取图像。最后在Transform中将每张图像都封装成Tensor。

class customData(Dataset):def __init__(self, img_path, txt_path, dataset = '', data_transforms=None, loader = default_loader):with open(txt_path) as input_file:lines = input_file.readlines()self.img_name = [os.path.join(img_path, line.strip().split('\t')[0]) for line in lines]self.img_label = [int(line.strip().split('\t')[-1]) for line in lines]self.data_transforms = data_transformsself.dataset = datasetself.loader = loaderdef __len__(self):return len(self.img_name)def __getitem__(self, item):img_name = self.img_name[item]label = self.img_label[item]img = self.loader(img_name)if self.data_transforms is not None:try:img = self.data_transforms[self.dataset](img)except:print("Cannot transform image: {}".format(img_name))return img, label

定义好了数据读取接口后,怎么用呢?

在代码中可以这样调用。

 image_datasets = {x: customData(img_path='/ImagePath',txt_path=('/TxtFile/' + x + '.txt'),data_transforms=data_transforms,dataset=x) for x in ['train', 'val']}

这样返回的image_datasets就和用torchvision.datasets.ImageFolder类返回的数据类型一样,有点狸猫换太子的感觉,这就是在第一篇博客中说的写代码类似搭积木的感觉。

有了image_datasets,然后依然用torch.utils.data.DataLoader类来做进一步封装,将这个batch的图像数据和标签都分别封装成Tensor。

 dataloders = {x: torch.utils.data.DataLoader(image_datasets[x],batch_size=batch_size,shuffle=True) for x in ['train', 'val']}

另外,每次迭代生成的模型要怎么保存呢?非常简单,那就是用torch.save。输入就是你的模型和要保存的路径及模型名称,如果这个output文件夹没有,可以手动新建一个或者在代码里面新建。

torch.save(model, 'output/resnet_epoch{}.pkl'.format(epoch))

最后,关于多GPU的使用,PyTorch支持多GPU训练模型,假设你的网络是model,那么只需要下面一行代码(调用 torch.nn.DataParallel接口)就可以让后续的模型训练在0和1两块GPU上训练,加快训练速度。

 model = torch.nn.DataParallel(model, device_ids=[0,1])

完整代码请移步:Github

每个类的图片放在一个文件夹

这是一个适合PyTorch入门者看的博客。PyTorch的文档质量比较高,入门较为容易,这篇博客选取官方链接里面的例子,介绍如何用PyTorch训练一个ResNet模型用于图像分类,代码逻辑非常清晰,基本上和许多深度学习框架的代码思路类似,非常适合初学者想上手PyTorch训练模型(不必每次都跑mnist的demo了)。接下来从个人使用角度加以解释。解释的思路是从数据导入开始到模型训练结束,基本上就是搭积木的方式来写代码。

首先是数据导入部分,这里采用官方写好的torchvision.datasets.ImageFolder接口实现数据导入。这个接口需要你提供图像所在的文件夹,就是下面的data_dir=‘/data’这句,然后对于一个分类问题,这里data_dir目录下一般包括两个文件夹:train和val,每个文件件下面包含N个子文件夹,N是你的分类类别数,且每个子文件夹里存放的就是这个类别的图像。这样torchvision.datasets.ImageFolder就会返回一个列表(比如下面代码中的image_datasets[‘train’]或者image_datasets[‘val]),列表中的每个值都是一个tuple,每个tuple包含图像和标签信息。

data_dir = '/data'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),data_transforms[x]), for x in ['train', 'val']}

另外这里的data_transforms是一个字典,如下。主要是进行一些图像预处理,比如resize、crop等。实现的时候采用的是torchvision.transforms模块,比如torchvision.transforms.Compose是用来管理所有transforms操作的,torchvision.transforms.RandomSizedCrop是做crop的。需要注意的是对于torchvision.transforms.RandomSizedCrop和transforms.RandomHorizontalFlip()等,输入对象都是PIL Image,也就是用python的PIL库读进来的图像内容,而transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])的作用对象需要是一个Tensor,因此在transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])之前有一个 transforms.ToTensor()就是用来生成Tensor的。另外transforms.Scale(256)其实就是resize操作,目前已经被transforms.Resize类取代了。

data_transforms = {'train': transforms.Compose([transforms.RandomSizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),'val': transforms.Compose([transforms.Scale(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),
}

前面torchvision.datasets.ImageFolder只是返回list,list是不能作为模型输入的,因此在PyTorch中需要用另一个类来封装list,那就是:torch.utils.data.DataLoader。torch.utils.data.DataLoader类可以将list类型的输入数据封装成Tensor数据格式,以备模型使用。注意,这里是对图像和标签分别封装成一个Tensor。这里要提到另一个很重要的类:torch.utils.data.Dataset,这是一个抽象类,在pytorch中所有和数据相关的类都要继承这个类来实现。比如前面说的torchvision.datasets.ImageFolder类是这样的,以及这里的torch.util.data.DataLoader类也是这样的。所以当你的数据不是按照一个类别一个文件夹这种方式存储时,你就要自定义一个类来读取数据,自定义的这个类必须继承自torch.utils.data.Dataset这个基类,最后同样用torch.utils.data.DataLoader封装成Tensor。

dataloders = {x: torch.utils.data.DataLoader(image_datasets[x],     batch_size=4, shuffle=True,num_workers=4) for x in ['train', 'val']}

生成dataloaders后再有一步就可以作为模型的输入了,那就是将Tensor数据类型封装成Variable数据类型,来看下面这段代码。dataloaders是一个字典,dataloders[‘train’]存的就是训练的数据,这个for循环就是从dataloders[‘train’]中读取batch_size个数据,batch_size在前面生成dataloaders的时候就设置了。因此这个data里面包含图像数据(inputs)这个Tensor和标签(labels)这个Tensor。然后用torch.autograd.Variable将Tensor封装成模型真正可以用的Variable数据类型。
为什么要封装成Variable呢?在pytorch中,torch.tensor和torch.autograd.Variable是两种比较重要的数据结构,Variable可以看成是tensor的一种包装,其不仅包含了tensor的内容,还包含了梯度等信息,因此在神经网络中常常用Variable数据结构。那么怎么从一个Variable类型中取出tensor呢?也很简单,比如下面封装后的inputs是一个Variable,那么inputs.data就是对应的tensor。

for data in dataloders['train']:inputs, labels = dataif use_gpu:inputs = Variable(inputs.cuda())labels = Variable(labels.cuda())else:inputs, labels = Variable(inputs), Variable(labels)

封装好了数据后,就可以作为模型的输入了。所以要先导入你的模型。在PyTorch中已经默认为大家准备了一些常用的网络结构,比如分类中的VGG,ResNet,DenseNet等等,可以用torchvision.models模块来导入。比如用torchvision.models.resnet18(pretrained=True)来导入ResNet18网络,同时指明导入的是已经预训练过的网络。因为预训练网络一般是在1000类的ImageNet数据集上进行的,所以要迁移到你自己数据集的2分类,需要替换最后的全连接层为你所需要的输出。因此下面这三行代码进行的就是用models模块导入resnet18网络,然后获取全连接层的输入channel个数,用这个channel个数和你要做的分类类别数(这里是2)替换原来模型中的全连接层。这样网络结果也准备好。

model = models.resnet18(pretrained=True)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 2)

但是只有网络结构和数据还不足以让代码运行起来,还需要定义损失函数。在PyTorch中采用torch.nn模块来定义网络的所有层,比如卷积、降采样、损失层等等,这里采用交叉熵函数,因此可以这样定义:

criterion = nn.CrossEntropyLoss()

然后你还需要定义优化函数,比如最常见的随机梯度下降,在PyTorch中是通过torch.optim模块来实现的。另外这里虽然写的是SGD,但是因为有momentum,所以是Adam的优化方式。这个类的输入包括需要优化的参数:model.parameters(),学习率,还有Adam相关的momentum参数。现在很多优化方式的默认定义形式就是这样的。

optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

然后一般还会定义学习率的变化策略,这里采用的是torch.optim.lr_scheduler模块的StepLR类,表示每隔step_size个epoch就将学习率降为原来的gamma倍。

scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)

准备工作终于做完了,要开始训练了。

首先训练开始的时候需要先更新下学习率,这是因为我们前面制定了学习率的变化策略,所以在每个epoch开始时都要更新下:

scheduler.step()

然后设置模型状态为训练状态:

model.train(True)

然后先将网络中的所有梯度置0:

optimizer.zero_grad()

然后就是网络的前向传播了:

outputs = model(inputs)

然后将输出的outputs和原来导入的labels作为loss函数的输入就可以得到损失了:

loss = criterion(outputs, labels)

输出的outputs也是torch.autograd.Variable格式,得到输出后(网络的全连接层的输出)还希望能到到模型预测该样本属于哪个类别的信息,这里采用torch.max。torch.max()的第一个输入是tensor格式,所以用outputs.data而不是outputs作为输入;第二个参数1是代表dim的意思,也就是取每一行的最大值,其实就是我们常见的取概率最大的那个index;第三个参数loss也是torch.autograd.Variable格式。

 _, preds = torch.max(outputs.data, 1)

计算得到loss后就要回传损失。要注意的是这是在训练的时候才会有的操作,测试时候只有forward过程。

loss.backward()

回传损失过程中会计算梯度,然后需要根据这些梯度更新参数,optimizer.step()就是用来更新参数的。optimizer.step()后,你就可以从optimizer.param_groups[0][‘params’]里面看到各个层的梯度和权值信息。

optimizer.step()

这样一个batch数据的训练就结束了!当你不断重复这样的训练过程,最终就可以达到你想要的结果了。

另外如果你有gpu可用,那么包括你的数据和模型都可以在gpu上操作,这在PyTorch中也非常简单。判断你是否有gpu可以用可以通过下面这行代码,如果有,则use_gpu是true。

use_gpu = torch.cuda.is_available()

完整代码请移步:Github

转载于:https://www.cnblogs.com/kk17/p/10105862.html

[Pytorch]PyTorch Dataloader自定义数据读取相关推荐

  1. Pytorch Note52 灵活的数据读取介绍

    Pytorch Note52 灵活的数据读取介绍 文章目录 Pytorch Note52 灵活的数据读取介绍 灵活的数据读取 读入数据 传入数据预处理方式 Dataset DataLoader 例子 ...

  2. TensorFlow 教程 --进阶指南--3.7自定义数据读取

    基本要求: 熟悉 C++ 编程. 确保下载 TensorFlow 源文件, 并可编译使用. 我们将支持文件格式的任务分成两部分: 文件格式: 我们使用 Reader Op来从文件中读取一个 recor ...

  3. PyTorch实现自由的数据读取

    北京 上海巡回站 | NVIDIA DLI深度学习培训 2018年1月26/1月12日 NVIDIA 深度学习学院 带你快速进入火热的DL领域 阅读全文                        ...

  4. [Pytorch] Sampler, DataLoader和数据batch的形成

    目录 1. 简介 2. 整体流程 3. Sampler和BatchSampler 3.1 Sampler 3.2 BatchSampler 4. DataLoader 4.1 DataLoader 4 ...

  5. 【小白学习PyTorch教程】五、在 PyTorch 中使用 Datasets 和 DataLoader 自定义数据

    「@Author:Runsen」 有时候,在处理大数据集时,一次将整个数据加载到内存中变得非常难. 因此,唯一的方法是将数据分批加载到内存中进行处理,这需要编写额外的代码来执行此操作.对此,PyTor ...

  6. 在pytorch中自定义dataset读取数据2021-1-8学习笔记

    在pytorch中自定义dataset读取数据 utils import os import json import pickle import randomimport matplotlib.pyp ...

  7. pytorch Dataset, DataLoader产生自定义的训练数据

    pytorch Dataset, DataLoader产生自定义的训练数据 目录 pytorch Dataset, DataLoader产生自定义的训练数据 1. torch.utils.data.D ...

  8. Pytorch数据读取(Dataset, DataLoader, DataLoaderIter)

    Pytorch的数据读取主要包含三个类: Dataset DataLoader DataLoaderIter 这三者是一个依次封装的关系: 1.被装进2., 2.被装进3. Dataset类 Pyto ...

  9. python读取data_Python批处理数据读取方法的细节:dataloader,Pytorch,批量,详解,DataLoader...

    在训练模型的过程中,我们需要不断的读取小批量的数据样本.Pytorch提供了 data 包来读取数据.接下来我将人工生成一些数据,然后使用 data 包来处理数据. import torch impo ...

  10. PyTorch框架学习八——PyTorch数据读取机制(简述)

    PyTorch框架学习八--PyTorch数据读取机制(简述) 一.数据 二.DataLoader与Dataset 1.torch.utils.data.DataLoader 2.torch.util ...

最新文章

  1. java预备作业2 计科1501 乔赫
  2. linux练习手册,Linux操作习题集(1)
  3. Python爬虫之pyppeteer去除Chrome正受到自动测试软件的控制(反爬策略)
  4. 学习计划(11.5)
  5. 如何打造高绩效团队?团队成功的关键要素?
  6. Linux中有play命令吗,linux play命令
  7. 什么是EV SSL证书
  8. Filezilla使用教程
  9. linux原生桌面,亲手打造自己的Linux桌面环境
  10. 19-图片标签注意点
  11. 职业操盘手的止损法则
  12. Redis分布式算法原理(重点)
  13. 使用视频作为网页背景的写法
  14. 如何用java创建一个文件
  15. 操作系统(一)——操作系统概述
  16. 「镁客·请讲」OracleChain老狼:EOS智能合约生态唯上,超级节点的竞争,不看吹牛先看做事...
  17. 站间切换反传介绍(PDU级/DRB级反传)
  18. 尚硅谷数据结构与算法(Java)--17--归并排序
  19. hive on spark 线上问题排查案例分享
  20. 20220714暑期实习笔记-下午

热门文章

  1. vue 中indexof_前端小知识-Vue中使用indexOf() 方法
  2. 系统学习深度学习(四十一)--AlphaGo Zero强化学习原理
  3. enclosing type java_Java ResolvedJavaType.getEnclosingType方法代码示例
  4. cpu爆了怎么排查和处理_CPU飙高,系统性能问题如何排查?
  5. java创建hbase多个列族_Spark:DataFrame写HFile (Hbase)一个列族、一个列扩展一个列族、多个列...
  6. while求和java,while语句基本练习(求和思想,统计思想)
  7. 浏览器接收响应消息并显示内容
  8. kafka性能优化入门
  9. Linux上将二进制文件转化为c语言数组
  10. 什么是服务的熔断降级