介绍
通常,对于许多特定领域的问题,数据的缺乏会阻碍深度神经网络的有效性,甚至不允许使用。然而,最近的生成对抗性网络(Gans)架构允许我们通过创建新的样本来捕捉数据分布中的复杂细节、纹理和变化,从而综合地增加数据。这些合成数据可以作为深度神经网络的额外训练输入,从而使数据有限的领域任务变得更加可行。
在该项目中,我们将具有自适应鉴别器增强(ADA)的NVIDIA Stylegan-2应用于小型胸部CT扫描数据集。此外,我们建立了一个CNN分类器来区分正常扫描和肿瘤扫描。通过将不同比例的合成生成数据注入到不同模型的训练中,我们能够评估具有所有真实数据的模型和具有真实合成混合数据的模型之间的性能差异。
Stylegan-2 ADA
NVIDIA在Neurips 2020论文“使用有限数据训练生成对抗性网络”中首次介绍了使用ADA的Stylegan-2。过去,在小数据集上训练GAN通常会导致网络鉴别器过拟合。因此,鉴别器倾向于记住训练集的噪声和异常值的模式,而不是学习数据分布的一般趋势,而不是学习区分真实数据和生成的数据。为了解决这个问题,Ada根据训练过程中观察到的过拟合程度动态调整数据增强的强度。这有助于模型更好地泛化,并在较小的数据集上获得更好的GAN性能。
扩充数据集
为了使用StyleGan-2 ADA模型,我们使用了来自GitHub的官方NVIDIA模型实现,请注意,这是Stylegan-3回购,但Stylegan-2仍然可以运行。
!git clone https://github.com/NVlabs/stylegan3clone https://github.com/NVlabs/stylegan3
根据你的设置,你可能必须安装依赖项并执行一些其他预处理。例如,我们选择将数据集图像的大小调整和缩小为224x224,因为我们只能访问单个GPU,而使用更大的图像大小在计算上要昂贵得多。我们之所以选择使用224x224,是因为我们为CNN选择的预训练模型ResNet经过了优化,可以处理这种大小的图像。
!pip install pillow
from PIL import Image
import os
'''Loops through the files in an input folder (input_folder), resizes them to a
specified new size (new_size), an adds them to an output folder (output_folder).'''
def resize_images_in_folder(input_folder, output_folder, new_size):
# Loop through all files in the input folder
for filename in os.listdir(input_folder):
input_path = os.path.join(input_folder, filename)
# Check if the file is an image
if os.path.isfile(input_path) and filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')):
# Open the image file
image = Image.open(input_path)
#Convert to RGB
image = image.convert('RGB')
# Resize the image
resized_image = image.resize(new_size)
# Generate the output file path
output_path = os.path.join(output_folder, filename)
# Save the resized image to the output folder
resized_image.save(output_path)
print(f"Resized {filename} and saved to {output_path}")
要开始培训过程,请导航到克隆存储库的目录,然后运行以下命令。
import os
!python dataset_tool.py --source= "Raw Data Directory" --dest="Output Directory" --resolution='256x256'
# Training
EXPERIMENTS = "Output directory where the Network Pickle File will be saved""
DATA = "Your Training DataSet Directory"
SNAP = 10
KIMG = 80
# Build the command and run it
cmd = f"/usr/bin/python3 /content/stylegan3/train.py --snap {SNAP} --outdir {EXPERIMENTS} --data {DATA} --kimg {KIMG} --cfg stylegan2 --gpus 1 --batch 8 --gamma 50"
!{cmd}
SNAP是指在你想要拍摄网络快照并将其保存到pickle文件之后的滴答数(显示信息的训练步骤)。
KIMG指的是你想要输入到GAN中的数千个图像的数量。
Gamma确定正则化对鉴别器的影响程度。
一旦你的模型完成了训练(这可能需要几个小时,取决于你的计算资源),你现在可以使用你训练的网络来生成图像。
pickle_file = "Network_Snapshot.pkl"
model_path = f'Path to Pickle File/{pickle_file}'
SAMPLES = Number of samples you want to generate
!python /content/stylegan3/gen_images.py --outdir=Output Directory --trunc=1 --seeds {SAMPLES} \
--network=$model_path
迁移学习卷积神经网络
为了对我们综合生成的数据的有效性进行基准测试,我们首先在原始数据上训练了一个CNN模型。一旦我们在测试集上有了基准精度,我们就用训练组合中越来越多的合成数据重新训练模型。
为了将我们的数据提供给模型,我们使用了Keras数据生成器,它将样本直接从指定的目录流入模型。原始数据集有4类不同类型的癌症,然而,为了简单起见,我们将其转化为二元分类问题。我们决定从原始Kaggle数据集中处理的两个类是正常类和鳞状类。
# Define directories for training, validation, and test datasets
train_dir = 'Your training data directory'
test_dir = 'Your testing data directory'
val_dir = 'Your validation data directory'
# Utilize data genarators to flow directly from directories
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(224, 224),
batch_size=20,
class_mode='binary', #Use 'categorical' for multi-class classification
shuffle=True,
seed=42 )
val_generator = val_datagen.flow_from_directory(
val_dir,
target_size=(224, 224),
batch_size=20,
class_mode='binary',
shuffle=True )
test_generator = test_datagen.flow_from_directory(
test_dir,
target_size=(224, 224),
batch_size=20,
class_mode='binary',
shuffle=True )
为了构建我们的模型,我们首先使用ResNet50基础架构和模型权重。我们之所以选择使用ResNet50,是因为它具有中等规模的架构、良好的文档以及通过Keras的易用性。在使用ImageNet模型权重导入ResNet50后,我们冻结了ResNet50层,并在顶部添加了可训练的密集层,以帮助网络学习我们的特定分类任务。
我们还选择合并批处理标准化,这可以通过标准化层输入和减少内部协变量移位来实现更快的收敛和更稳定的训练[3]。此外,它可以提供正则化效果,有助于防止在我们添加的可训练密集层中出现过拟合。
最初,我们的模型表现不佳。我们通过将激活函数从RELU切换到泄漏RELU来解决这个问题。这表明我们的网络可能一直面临着死亡RELU或死亡神经元的问题。简而言之,由于RELU的梯度对于负数总是为零,这可能导致神经元“死亡”,并且对网络没有贡献。由于Leaky ReLU对于负值是非零的,因此使用它作为激活函数可以帮助解决这个问题。
结果
为了测试我们的合成数据,我们用0%、25%、50%、75%和100%的额外合成样本在5个单独的实例上训练上述CNN。例如,0%的合成样本意味着数据都是原始的,而100%意味着训练集包含等量的原始数据和合成数据。然后,对于每个网络,我们在一组真实的未见测试数据上使用精度度量来评估性能。下图显示了不同比例的合成数据如何影响测试精度。
训练模型是不稳定的,因此我们排除了精度为1.0或极低的迭代。这帮助我们避免了训练迭代过低或过高。
我们可以看到,从0%到25%,我们看到测试精度急剧增加,这表明即使对数据集进行少量扩充,也会对数据最初很小的问题产生很大影响。
由于我们只在80KIMG上训练我们的GAN(由于计算限制),如果有更多的GAN训练迭代,我们的合成数据的质量可能会更好。值得注意的是,合成数据质量的提高也会影响上图。我们假设合成质量的提高也将导致训练中使用的合成数据的最佳比例的增加。此外,如果合成图像能够更好地拟合我们的训练数据的真实分布,则我们可以在模型训练中合并更多的合成图像,而不会出现过拟合。
结论
在这个项目中,使用GAN来扩充有限的数据已被证明是一种有效的技术,可以扩展训练集,更重要的是,可以提高分类精度。虽然我们选择了一个小而基本的问题,但这可以很容易地以几种方式升级。未来的工作可能包括使用更多的计算资源来获得更好的合成样本,在分类任务中引入更多的类别(使其成为一个多类问题),以及试验更新的GAN架构。无论如何,使用GAN来扩充小数据集现在可以将许多以前数据有限的问题纳入深度神经网络的范围。