动手学习深度学习keras版——从零开始实现Vnet 2D版

article/2025/9/25 6:31:14

从零开始实现Vnet 2D版

  • 1. 数据处理
    • 1.1 数据集介绍
    • 1.2 数据提取和转换
    • 1.3 Keras的数据生成器(generator)构造
  • 2. Vnet 2D版网络实现
    • 2.1 Loss函数设计
    • 2.2 网络结构实现
  • 3. 开始训练啦
  • 4. 网络预测(inference)
  • 5. 结果展示
  • 6. 踩坑经验总结

  工作需要,暂时换成keras来写网络代码。其实感觉还是pytorch用起来灵活整洁一些。有时间还是会继续出pytorch版的,顺便看看两个深度学习框架之间的差别。
  文中的代码是根据github上的一个项目进行修改的,借用了他的思路,因此在此放出参考项目的链接:https://github.com/FENGShuanglang/2D-Vnet-Keras

1. 数据处理

1.1 数据集介绍

  由于这是医疗图像领域的网络,所以我也特地去找了医疗图像的分割任务数据集,数据集来源是:https://warwick.ac.uk/fac/sci/dcs/research/tia/glascontest/download/。
  这个数据集的分割任务其实很简单,就是找出图像中的目标细胞即可。是个二分类任务,只分为前景和背景。下图是一个样本及其mask标签(已经经过可视化处理),可以看到,其实就是寻找细胞的分割任务。另外,原数据集的样本数据是实例分割任务,也就是说,图中的三个细胞,其实在原来的标签里分别以数值1,2,3储存。实例分割就是不单单区分目标的类别,同种类的不同实例也属于不同类别。为了简化任务,我们把任务改成语义分割任务,即只需要分割目标的种类即可,不用分割具体实例。所以才有了下图的样本图像。
在这里插入图片描述在这里插入图片描述

1.2 数据提取和转换

  下载数据集后,按下图新建文件夹,文件夹的名字也很好理解,比如"SegTrainImg"里存放的是训练用的图像,"SegTrainMaskImg"存放的是对应训练图像的mask图像。建这么多文件夹是因为keras读取数据的方式决定的,这样可以免去自己写读取数据的繁琐过程。
在这里插入图片描述
  我自己写了个脚本把原图像数据集文件夹内的图像分别复制到对应六个文件夹中,这样快一点,省的自己复制。代码如下:

import os
import cv2
def data_prepare():"""将图像分割用的图片从JPEGImages文件夹提取到SegTrainImg和SegValImg里"""dataset_path = r'D:\My_project\deeplearning\datasets\warwick_qu_dataset'imgpath = r'D:\My_project\deeplearning\datasets\warwick_qu_dataset\Warwick_QU_Dataset'trainimg_savepath = os.path.join(dataset_path,'SegTrainImg')trainmask_savepath = os.path.join(dataset_path, 'SegTrainMaskImg')valimg_savepath = os.path.join(dataset_path,'SegValImg')valmask_savepath = os.path.join(dataset_path, 'SegValMaskImg')testimg_savepath = os.path.join(dataset_path,'SegtestImg')testmask_savepath = os.path.join(dataset_path, 'SegTestMask')filelist = os.listdir(imgpath)for file in filelist:if 'testA' in file:img = cv2.imread(os.path.join(imgpath,file))savepath = os.path.join(valimg_savepath,file) if 'anno' not in file else os.path.join(valmask_savepath,file)cv2.imwrite(savepath,img)elif 'testB' in file:img = cv2.imread(os.path.join(imgpath, file))savepath = os.path.join(testimg_savepath, file) if 'anno' not in file else os.path.join(testmask_savepath,file)cv2.imwrite(savepath, img)elif 'train' in file:img = cv2.imread(os.path.join(imgpath, file))savepath = os.path.join(trainimg_savepath, file) if 'anno' not in file else os.path.join(trainmask_savepath,file)cv2.imwrite(savepath, img)print("Done")

  处理好后,可以得到85张训练集、60张验证集以及20张测试集图像。数据集不大,倒是很符合医学图像的情况。这样训练起来也很快。硬件设备不够的同学(比如我)跑起代码来就很舒服了。

1.3 Keras的数据生成器(generator)构造

  简要说明一下Keras的数据集生成原理。Keras提供了一个keras.preprocessing.image.ImageDataGenerator类,可以很方便的进行数据增广和数据生成。具体的步骤如下:
  1). 构造ImageDataGenerator类实例,其中传入需要的数据增广参数,提供的参数可以查阅keras官方文档;
  2). 使用ImageDataGenerator类设置读取数据的位置和方式,总共有三种方式,我采用的是".flow_from_directory()"函数,这应该是最方便,也最省内存空间的方式,因为它不需要提前加载所有数据,只有需要的时候才会提取。
  3). 用关键字yield构造python的生成器,此时该生成器函数就是对应数据集的生成器。

  光看文字不太好理解,下面上代码:

DATA_PATH = r'..\datasets\warwick_qu_dataset'  # 数据集文件夹路径def train_generator(img_size, batch_size, gen_arg_dict={}, seed=1):"""训练数据生成器:param img_size: 生成的目标图片尺寸:param batch_size: 批量大小:param gen_arg_dict: 数据增广参数:param seed: 随机抽样的随机种子:return: 标准化后的图像以及转换为类别序号的mask"""train_datagen = ImageDataGenerator(**gen_arg_dict)  # 设置数据增广实例gen_arg_dict['rescale'] = 1  # mask不需要标准化,方便后续处理mask_datagen = ImageDataGenerator(**gen_arg_dict)  # mask的数据增广应当和原始图片一模一样# 加载数据发生器,注意,classes是存放img/mask数据的文件夹名称,且img/mask两者的随机种子seed和batchsize要保持一致img_generator = train_datagen.flow_from_directory(DATA_PATH,classes=['SegTrainImg'],target_size=img_size,seed=seed,batch_size=batch_size)mask_generator = mask_datagen.flow_from_directory(DATA_PATH,classes=['SegTrainMaskImg'],target_size=img_size,seed=seed,batch_size=batch_size)train_generator = zip(img_generator,mask_generator)  # 将图片数据和mask数据整合for(img, mask) in train_generator:img = img[0]mask = mask2label(mask[0])yield (img,mask)

  其中有几点要说明。参数gen_arg_dict是数据增广的参数字典,前面的**是字典分解。不这么写,直接写参数名和数值也可以。.flow_from_directory()函数中,第一个参数是数据的总文件夹路径,内含训练集、测试集等数据文件夹。classes参数是输入对应数据的文件夹名称,比如’SegTrainImg’就是训练集图像的文件夹名称。其实flow_from_directory()函数就是调用某个文件夹下的所有图像文件,并根据设置好的参数进行数据增广的数据生成器(即img_generator,mask_generator)。
  注意,生成器最终输入到网络中的数据是“yield (img,mask)”这条语句返回的img,mask数据。如果需要在ImageDataGenerator的数据增广外,另外做其他的数据预处理,可以自己编写函数,只要保证数据格式能输入到网络即可。比如上面代码中的mask2label()函数,就是对mask函数进行额外处理的,具体代码见下面:

def mask2label(mask):"""将原始的mask图像转换为label数据格式,即按类别顺序分为0,1,2,...:param mask: 原始mask图像:return: 转换后的label"""mask[mask>0] = 1mask = mask[:,:,:,0]mask = mask[:,:,:,np.newaxis]return mask

  同理,可以构建验证集数据生成器和测试集数据生成器。

def val_generator(img_size, batch_size=1):val_datagen = ImageDataGenerator(rescale=1./255)img_generator = val_datagen.flow_from_directory(DATA_PATH,classes=['SegValImg'],target_size=img_size,batch_size=batch_size,seed=1)mask_datagen = ImageDataGenerator()mask_generator = mask_datagen.flow_from_directory(DATA_PATH, classes=['SegValMaskImg'], target_size=img_size,batch_size=batch_size, seed=1)val_generator = zip(img_generator, mask_generator)  # 将图片数据和mask数据整合for (img,mask) in val_generator:img = img[0]mask = mask2label(mask[0])yield (img,mask)def test_generator(img_size, batch_size=1):test_datagen = ImageDataGenerator(rescale=1./255)img_generator = test_datagen.flow_from_directory(DATA_PATH,classes=['SegtestImg'],target_size=img_size,batch_size=batch_size)for img in img_generator:img = img[0]yield img

  另外,还是提醒一下,和pytorch的教程里一样,写完数据生成器,一定要检查一下数据是否正常,不是网络能跑就可以的,一定要检验输入的数据是我们设定好的数据,而不是错误的数据。

2. Vnet 2D版网络实现

2.1 Loss函数设计

  正如分析论文的博客里提到的那样,Vnet使用的是Dice指标和Dice损失函数。具体该损失函数的含义可以参考链接里的博客。代码其实很简单,至于用在哪下文会具体阐述:

def dice_coef(y_true, y_pred):"""dice指标"""smooth = 1e-6  # 防止分母为0的极小值y_true_f =y_true# K.flatten(y_true)y_pred_f =y_pred# K.flatten(y_pred)intersection = K.sum(y_true_f * y_pred_f,axis=(0,1,2))denom =K.sum(y_true_f,axis=(0,1,2)) + K.sum(y_pred_f,axis=(0,1,2))return K.mean((2. * intersection + smooth) /(denom + smooth))def dice_loss(smooth, thresh):"""dice_loss,注意"""def dice(y_true, y_pred):return 1-dice_coef(y_true, y_pred)return dice

2.2 网络结构实现

在这里插入图片描述  从网络结构图可以看出,Vnet的网络主要分为左右两侧,且两侧结构十分相似,每个stage之间也有规律。因此,构建网络的时候可以用点技巧,不用一层层的搭建,那样太麻烦了。为压缩路径和扩展路径分别写了两个子函数进行构建,即downstage_resBlock和upstage_resBlock:

def downstage_resBlock(x, stage_id, keep_prob, stage_num=5):"""Vnet左侧的压缩路径的一个stage层:param x: 该stage的输入:param stage_id: int,表示第几个stage,原论文中从上到下依次是1-5:param keep_prob: dropout保留元素的概率,如果不需要则设置为1:param stage_num: stage_num是Vnet设置的stage总数:return: stage下采样后的输出和stage下采样前的输出,下采样前的输出需要与Vnet右侧的扩展路径连接,所以需要输出保存。"""x0 = x  # x0是stage的原始输入# Vnet每个stage的输入会进行特定次数的卷积操作,1~3个stage分别执行1~3次卷积,3以后的stage均执行3次卷积# 每个stage的通道数(卷积核个数或叫做feature map数量)依次增加两倍,从16,32,64,128到256for _ in range(3 if stage_id > 3 else stage_id):x=PReLU()(BatchNormalization()(Conv2D(16 * (2 ** (stage_id - 1)), 5, activation=None, padding ='same', kernel_initializer ='he_normal')(x)))print('conv_down_stage_%d:' %stage_id,x.get_shape().as_list())#输出收缩路径中每个stage内的卷积x_add=PReLU()(add([x0, x]))x_add=Dropout(keep_prob)(x_add)if stage_id<stage_num:x_downsample=PReLU()(BatchNormalization()(Conv2D(16 * (2 ** stage_id), 2, strides=(2, 2), activation=None, padding ='same', kernel_initializer ='he_normal')(x_add)))return x_downsample,x_add  # 返回每个stage下采样后的结果,以及在相加之后的结果else:return x_add,x_add  # 返回相加之后的结果,为了和上面输出保持一致,所以重复输出def upstage_resBlock(forward_x, x, stage_id):"""Vnet右侧的扩展路径的一个stage层:param forward_x: 对应压缩路径stage层下采样前的特征,与当前stage的输入进行叠加(不是相加),补充压缩损失的特征信息:param x: 当前stage的输入:param stage_id: 当前stage的序号,右侧stage的序号和左侧是一样的,从下至上是5到1:return:当前stage上采样后的输出"""input = concatenate([forward_x, x], axis=-1)for _ in range(3 if stage_id > 3 else stage_id):input=PReLU()(BatchNormalization()(Conv2D(16 * (2 ** (stage_id - 1)), 5, activation=None, padding='same', kernel_initializer='he_normal')(input)))print('conv_down_stage_%d:' % stage_id, x.get_shape().as_list())  # 输出收缩路径中每个stage内的卷积conv_add=PReLU()(add([x, input]))if stage_id>1:# 上采样的卷积也称为反卷积,或者叫转置卷积conv_upsample=PReLU()(BatchNormalization()(Conv2DTranspose(16 * (2 ** (stage_id - 2)), 2, strides=(2, 2), padding='valid', activation=None, kernel_initializer='he_normal')(conv_add)))return conv_upsampleelse:return conv_add

  利用这两个子函数,就可以很方便的搭建出Vnet的网络如下:

def Vnet(pretrained_weights=None, input_size = (256, 256, 1), num_class=1, is_training=True, stage_num=5):"""Vnet网络构建:param pretrained_weights:是否加载预训练参数:param input_size: 输入图像尺寸(w,h,c),c是通道数:param num_class:  数据集的类别总数:param is_training:  是否是训练模式:param stage_num:  Vnet的网络深度,即stage的总数,论文中为5:return: Vnet网络模型"""keep_prob = 0.5 if is_training else 1.0  # dropout概率left_featuremaps=[]input_data = Input(input_size)x = PReLU()(BatchNormalization()(Conv2D(16, 5, activation = None, padding = 'same', kernel_initializer='he_normal')(input_data)))# 数据经过Vnet左侧压缩路径处理for s in range(1,stage_num+1):x, featuremap=downstage_resBlock(x, s, keep_prob, stage_num)left_featuremaps.append(featuremap)  # 记录左侧每个stage下采样前的特征# Vnet左侧路径跑完后,需要进行一次上采样(反卷积)x_up = PReLU()(BatchNormalization()(Conv2DTranspose(16 * (2 ** (s - 2)),2,strides=(2, 2),padding='valid',activation=None, kernel_initializer='he_normal')(x)))# 数据经过Vnet右侧扩展路径处理for d in range(stage_num-1,0,-1):x_up = upstage_resBlock(left_featuremaps[d - 1], x_up, d)if num_class>1:conv_out=Conv2D(num_class, 1, activation='softmax', padding = 'same', kernel_initializer = 'he_normal')(x_up)else:conv_out=Conv2D(num_class, 1, activation='sigmoid', padding = 'same', kernel_initializer = 'he_normal')(x_up)model=Model(inputs=input_data,outputs=conv_out)print(model.output_shape)model_dice=dice_loss(smooth=1e-5,thresh=0.5)  # dice损失函数,二分类时可以使用,多分类需要修改if num_class > 1:model.compile(optimizer=SGD(lr=0.001,momentum=0.99,decay=1e-6), loss='sparse_categorical_crossentropy', metrics = ['ce'])  # metrics看看需不需要修改else:model.compile(optimizer=SGD(lr=0.001, momentum=0.99, decay=1e-6), loss='binary_crossentropy',metrics=['binary_accuracy'])# model.compile(optimizer=SGD(lr=0.001, momentum=0.99, decay=1e-6), loss=dice_loss,metrics=[model_dice])  # 如果需要使用dice和dice_loss函数,则改为注释中的样子if pretrained_weights:model.load_weights(pretrained_weights)# plot_model(model, to_file='model.png')  # 绘制网络结构return model

  提醒一下,model.compile的时候,要非常注意loss和metrics的取值,这两者的选用要和数据、任务类型相匹配才行,如果不匹配,轻则报错无法训练,重则训练了很久得到的结果完全无法用。另外还要注意,input_data只能是Input()类,不要在下面的代码中将其他过程结果赋值给input_data,这样就无法定位到Input()类里了,最后在model=Model(inputs=input_data…)这条语句时,参数inputs就无法正确找到Input()类,会报错的。

3. 开始训练啦

  训练代码如下,还是比较简洁的,其中的注意点也在代码里注释了。

COLOR_DICT = {"cell":(255,255,255)}  # 主要是给多类别的时候使用的
CLASSES = list(COLOR_DICT.keys())  # 类别的名称listif __name__ == '__main__':batchsize = 10seed = 1img_size = (256, 256)gen_arg_dict = {"rescale": 1 / 255., "horizontal_flip": True, "vertical_flip":True, "rotation_range":20, "shear_range":0.1, "width_shift_range":0.1,"height_shift_range":0.1}  # 数据增广参数is_train = False  # 训练还是预测的标志if is_train:trainGen = train_generator(img_size, batchsize, gen_arg_dict)  # 构建训练集数据生成器valGen = val_generator(img_size)  # 验证集数据生成器model = Vnet(num_class=len(CLASSES), input_size=(256, 256, 3))  # 构建网络# 用来储存训练过程网络参数的回调函数,save_best_only=True是如果要保存的模型的指标不是最优的,就不保存了。# monitor就是判断网络效果的指标,verbose是输出方式可以忽略,mode和monitor配合,定义指标的以最大为最优还是最小为最优# period是每隔多少epoch保存一次模型model_checkpoint = ModelCheckpoint('Vnetweights_cellseg.{epoch:02d}-{val_loss:.2f}.hdf5', monitor='val_loss', verbose=1,save_best_only=True, mode='min',period=1)# 输出给tensorboard使用的信息的回调函数,具体可以百度用法tbCallBack = keras.callbacks.TensorBoard(log_dir='./graph',histogram_freq=0,write_graph=True,write_images=True)# 注意,这里的steps_per_epoch的数字需要自己计算,根据训练集和batchsize的数值计算。callbacks参数存放需要在训练过程中使用的回调函数model.fit_generator(trainGen, steps_per_epoch=8, epochs=100, validation_data=valGen, validation_steps=6,callbacks=[model_checkpoint,tbCallBack])else:# 预测的时候要注意,如果model.compile的时候损失函数和metrics使用的是自定义函数# 那么load_model的时候需要增加指定参数custom_objects={"dice":dice_loss(1e-5,0.5),"dice_coef":dice_coef}model = keras.models.load_model("Vnetweights_cellseg.11-0.71.hdf5")testGen = test_generator(img_size)  # 测试集数据生成器# 得到的pred结果是(20,256,256,1)的尺寸,代表20张预测图像的预测mask结果,其中数值>0.5意为是前景pred = model.predict_generator(testGen, 20, verbose=1)  savepath = r'..\datasets\warwick_qu_dataset\SegTestMask'decode_and_save(pred,savepath)  # 将pred储存的数据进行解码,并保存解码后预测的mask图像

4. 网络预测(inference)

  预测时,修改好训练保存的网络参数名称后,修改is_train=False即可进行预测。网络预测后,得到的结果需要解码转换为所需的预测mask图像。该解码函数如下:

def decode_and_save(pred,savepath):"""将预测的数据转换为可视图并储存"""n = pred.shape[0]for i in range(n):if len(CLASSES)>1:ipred = pred[i, :, :, :]ipred = np.argmax(ipred, axis=2)img = np.zeros((ipred.shape[0], ipred.shape[1], 3), dtype='uint8')for r in range(ipred.shape[0]):for c in range(ipred.shape[1]):img[r, c, 2], img[r, c, 1], img[r, c, 0] = COLOR_DICT[CLASSES[ipred[r, c]]][0], \COLOR_DICT[CLASSES[ipred[r, c]]][1], \COLOR_DICT[CLASSES[ipred[r, c]]][2]cv2.imwrite(os.path.join(savepath, str(i) + '.jpg'), img)else:ipred = pred[i, :, :, :]ipred[ipred > 0.5] = 255ipred = ipred.astype(np.uint8)cv2.imwrite(os.path.join(savepath, str(i) + '.jpg'), ipred)

5. 结果展示

  随意跑了20个epoch,也没怎么调参,效果好像不是很好,但是也能看出个大概,贴上来大家看看。后续效果调好一点再增加更好的预测图像。
在这里插入图片描述 在这里插入图片描述
在这里插入图片描述 在这里插入图片描述

6. 踩坑经验总结

  写代码时候遇到的一些报错,想想还是记录一下比较好,省的以后又百度半天。

  • 经验1 报错信息如下:
    在这里插入图片描述这次报错是因为,我用代码来跑多分类任务,设计的label是整数型而不是one-hot,也就是说,label是类别的序号(0-n),而不是n维的onehot向量。所以,model.compile选择的loss=’ sparse_categorical_crossentropy’。原代码默认选择的metrics=[‘acc’],这是应用在二分类问题的评测标准,网络的输出与评测标准不一致,所以报错说shape不同。
    对于多分类问题,metrics要选择’ce’/’crossentropy’,这样问题解决。

    可以参考如下网站,里面有比较详细的什么问题使用什么metrics的介绍:
    https://www.cnblogs.com/weiyinfu/p/9783776.html

  • 经验2 报错信息:“tensorflow.python.framework.errors_impl. UnknownError: Failed to get convolution algorithm. This is probably because cuDNN failed to initialize, so try looking to see if a warning log message was printed above.”
    其实是keras的backend,也就是tensorflow的版本和CUDA或者CUDNN版本不匹配导致的。当时报错时我是用的是tensorflow-gpu 1.12.0 cuda 9.0 cudnn 7.0。后来重装为tensorflow-gpu 1.9.0,问题解决。

  • 经验3 报错信息如下:
    在这里插入图片描述
    这是因为在网络构建的时候,我们使用的是自己的loss或者metric函数,此时保存网络时,记录的loss名称是当时我们使用的loss函数名,上图中是“dice”。因此,在加载网络的时候,需要提供参数“custom_objects={“dice”:dice_loss(1e-5,0.5),“dice_coef”:dice_coef}”,这里我们使用了自己的loss和metric,所以提供了两个元素的字典。


http://chatgpt.dhexx.cn/article/4DZ4J01U.shtml

相关文章

安卓 VNET 抓取 wskey 教程

图文示例机型&#xff1a;一加8 就设置可能长得不一样&#xff0c;功能均一致&#xff0c;请根据个人系统设置进行证书安装操作 wskey 相对于 cookie 的有效期更长&#xff0c;可以通过 wskey 转换智能化管理后台&#xff0c;省心 下载安装 VNET 抓包 APP 文件文件大小&#xf…

azure mysql on vnet_管理 VNet 终结点 - Azure 门户 - Azure Database for MySQL | Microsoft Docs

您现在访问的是微软AZURE全球版技术文档网站&#xff0c;若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站&#xff0c;请访问 https://docs.azure.cn. 使用 Azure 门户创建和管理 Azure Database for MySQL VNet 服务终结点和 VNet 规则Create and manage Azure …

【Microsoft Azure 的1024种玩法】六十三.通过全局 VNet 对等互连实现同一区域不同网段的虚拟网络实时打通

【简介】 虚拟网络对等互连是两个虚拟网络之间的网络连接&#xff0c; 虚拟网络对等互连可以通过 Azure 主干网络连接同一区域或不同区域的虚拟网络进行打通实现实时通信&#xff0c;本篇文章主要介绍了如何通过全局 VNet 对等互连的方式将同一区域不同网段的虚拟网络中虚拟机…

【Azure】微软 Azure 基础解析(七)Azure 网络服务中的虚拟网络 VNet、网关、负载均衡器 Load Balancer

本系列博文还在更新中&#xff0c;收录在专栏&#xff1a;「Azure探秘&#xff1a;构建云计算世界」 专栏中。 本系列文章列表如下&#xff1a; 【Azure】微软 Azure 基础解析&#xff08;三&#xff09;描述云计算运营中的 CapEx 与 OpEx&#xff0c;如何区分 CapEx 与 OpEx…

好用的Android抓包神器 VNET

很多网友要我发前几个青龙面板抓变量用到软件&#xff0c;马上安排。 黑科技VNET 最-好用的Android抓包神器 VNET是Android平台下功能最强大的网络抓包工具&#xff0c;支持HTTP&HTTPS&#xff0c;TCP&UDP&#xff0c;IPv6&IPv4&#xff0c;多终端显示&#xff0…

爬虫从入门到精通(19) |安卓手机端抓包软件VNET介绍

提前声明&#xff1a;该专栏涉及的所有案例均为学习使用&#xff0c;如有侵权&#xff0c;请联系本人删帖&#xff01; 文章目录 一、前言二、介绍1.功能2.安装3.root和非root 一、前言 对于一些抓取较为严的软件&#xff0c;有时候我们不好抓到包&#xff0c;这个时候我们也可…

VNET原理与实现(1)

神经网络什么的早就不是新概念了&#xff0c;不过学了这么久&#xff0c;还一直在二维图像上打转&#xff0c;所以今天开始入手三维图像分割&#xff0c;先从可爱的VNET开始吧&#xff0c;从胖嘟嘟的外形看&#xff0c;这应该是个软柿子&#xff0c;那就试着捏一捏吧&#xff0…

UNet 、3D-UNet 、VNet 区别

UNet 、3D-UNet 、VNet 区别 医学图像的几个常用模型&#xff0c;简单总结一下。 三个model的代码在我的Github上&#xff0c;可以参考一下&#xff1a;https://github.com/VickyLLY/unet_and_vnet 文章目录 UNet 、3D-UNet 、VNet 区别一、UNet二、3D-UNet三、VNet 一、UNet…

程序员如何写一份更好的简历!!

概述 面试前要准备的第一件事就是写简历,从零开始写简历是一件痛苦的事,因为它既重要又耗时。现在就有求职者在电脑前急躁不安地搜索简历模版和参考例句,却不知道如何下笔。写得太短的话觉得没诚意,写得太长的话又无从下手。关键的是大多数求职者没有做面试官的经验,也没…

Java程序员简历模板

从「目标职位」的角度讲讲&#xff0c;如何做一份简历才能提高你拿到 Offer 的几率。 文章目录 简历重点一、HR如何刷简历二、简历排版顺序三、专业技能四、项目经验2013/06 -- 至今 伟业网上电商系统2012/03 -- 2012/08 人事管理系统 总结 简历重点 大家觉得简历就是自我赞歌…

程序员简历项目经验怎么写?

我是一个典型的互联网公司程序员&#xff0c;也见过无数的程序员简历&#xff0c;包括很多优秀的程序员简历&#xff0c;看了可以让人眼前一亮&#xff0c;优美简洁的简历模板&#xff0c;项目经验工作重点突出;也见过更多的写得不好的简历。程序员怎么写简历?程序员简历项目经…

程序员简历上写这种项目,难怪面试当炮灰。。。

目录&#xff1a; 高级工程师必备&#xff1a;系统设计能力如何让你的项目更有技术含量 上篇文章 《我只是把握好了这3点&#xff0c;1个月后成功拿下大厂offer&#xff01;》我们聊了聊Java工程师在跳槽前的1个月&#xff0c;如何利用较短的时间从技术广度、技术深度、基础功…

程序员如何写简历|附10个模版

卷友们好&#xff0c;我是rumor。 今天卷到简历这个事情上来了。千万不要误会&#xff0c;我没有在写自己的简历。 而是我经常会收到一些简历&#xff0c;有些是发到了邮箱里求内推&#xff0c;有些是卷友让我帮忙看一下&#xff0c;直到最近的某一天&#xff0c;我打开了一份…

【无标题】程序员个人简历模板

程序员个人简历模板1 姓 名&#xff1a; 国 籍&#xff1a; 中国 目前住地&#xff1a; 广州 民 族&#xff1a; 汉族 户 籍 地&#xff1a; 茂名 身高体重&#xff1a; 168 cm kg 婚姻状况&#xff1a; 未婚 年 龄&#xff1a; 28 岁 求职意向及工作经历 人才类型&#x…

Java程序员面试简历模板(30套简历模板+300套简历)

需要免费领取简历模板和简历套装欢迎加群862461829 【群里还含有&#xff1a;Java80g学习视频Java学习书籍Java项目实战源码安装软件等】 各类资源都有哦~ 简历是你吸引面试官的第一步&#xff0c;如何让你的平平无奇的简历包装的更好&#xff0c;而又足以让面试官相信你足够…

浅析海量数据处理问题

生活中我们经常会遇到一些海量数据处理的问题&#xff0c;那么怎样的问题就算是海量数据了呢&#xff1f;来看以下这几个问题&#xff1a; 给定一个大小超过 100G 的文件, 其中存在 IP 地址, 找到其中出现次数最多的 IP 地址 。给定100亿个整数, 找到其中只出现一次的整数(位图…

教你如何迅速秒杀掉:99%的海量数据处理面试题

教你如何迅速秒杀掉&#xff1a;99%的海量数据处理面试题 本文经过大量细致的优化后&#xff0c;收录于我的新书《 编程之法&#xff1a;面试和算法心得》第六章中&#xff0c;新书目前已上架 京东/ 当当 作者&#xff1a;July出处&#xff1a;结构之法算法之道blog 前言 一般而…

ORACLE如何处理海量数据

当前数据存在的问题: 一、 数据量过大,数据中什么情况都可能存在。如果说有10条数据,那么大不了每条去逐一检查,如果数据上到千万级别,甚至过亿,那不是手工能解决的了,必须通过工具或者程序进行处理,尤其海量的数据; 二、 软硬件要求高,系统资源占用率高。对海量的…

海量数据处理的 Top K相关问题

全栈工程师开发手册 &#xff08;作者&#xff1a;栾鹏&#xff09; python数据挖掘系列教程 Top-k的最小堆解决方法 问题描述&#xff1a;有N(N>>10000)个整数,求出其中的前K个最大的数。&#xff08;称作Top k或者Top 10&#xff09; 问题分析&#xff1a;由于(1)输…

海量数据处理面试题集锦

十七道海量数据处理面试题与Bit-map详解 作者&#xff1a;小桥流水&#xff0c;redfox66&#xff0c;July。 前言 本博客内曾经整理过有关海量数据处理的10道面试题&#xff08;十道海量数据处理面试题与十个方法大总结&#xff09;&#xff0c;此次除了重复了之前的10道面试题…