Tensorflow 如何设计一个最佳的CNN?

Tensorflow 如何设计一个最佳的CNN?,tensorflow,machine-learning,computer-vision,conv-neural-network,hyperparameters,Tensorflow,Machine Learning,Computer Vision,Conv Neural Network,Hyperparameters,我正在攻读博士学位。该项目的目标是减少地球上的二氧化碳排放 我有一个数据集,我能够成功地实现一个CNN,它提供了80%的准确率(最坏情况)。然而,我工作的领域要求很高,我的印象是,如果有一个经过优化的CNN,我可以获得更好的准确度 专家们如何设计CNN的节目?我如何在初始模块、退出正则化、批量规范化、卷积滤波器大小、卷积通道的大小和深度、完全连接层的数量、激活神经元等之间进行选择?人们如何以科学的方式处理这个大型优化问题?这种组合是无穷无尽的。是否有任何现实生活中的例子可以解决这个问题,解决它的

我正在攻读博士学位。该项目的目标是减少地球上的二氧化碳排放

我有一个数据集,我能够成功地实现一个
CNN
,它提供了
80%的准确率(最坏情况)。然而,我工作的领域要求很高,我的印象是,如果有一个经过优化的CNN,我可以获得更好的准确度

专家们如何设计CNN的节目?我如何在
初始
模块、
退出
正则化、
批量规范化
、卷积滤波器大小、卷积通道的大小和深度、完全连接层的数量、激活神经元等之间进行选择?人们如何以科学的方式处理这个大型优化问题?这种组合是无穷无尽的。是否有任何现实生活中的例子可以解决这个问题,解决它的全部复杂性(而不仅仅是优化一些超参数)


希望我的数据集不会太大,因此我正在考虑的
CNN
模型应该只有很少的参数。

我认为你对所需参数数量的估计有点偏差。想想看,如果你使用迁移学习,你会得到几百万。如果你愿意,你可以努力尝试制作自己的模型,但你很可能不会比迁移学习的结果更好(而且更可能没有那么好)。我强烈推荐MobileV2型号。现在,如果使用ReducelRon平台的可调学习率,您可以使该模型或任何其他模型的性能更好。我建议的另一件事是使用Keras回调earlystoping。文件是。将其设置为监视验证丢失,并将restore\u best\u weights=True。将历元数设置为一个较大的数字,以便触发此回调并返回具有来自验证损失最低的历元的权重的模型。我推荐的代码如下所示

height=224
width=224
img_shape=(height, width, 3)
dropout=.3
lr=.001
class_count=156 # number of classes
img_shape=(height, width, 3)
base_model=tf.keras.applications.MobileNetV2( include_top=False, input_shape=img_shape, pooling='max', weights='imagenet') 
x=base_model.output
x=keras.layers.BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001 )(x)
x = Dense(512, kernel_regularizer = regularizers.l2(l = 0.016),activity_regularizer=regularizers.l1(0.006),
                bias_regularizer=regularizers.l1(0.006) ,activation='relu', kernel_initializer= tf.keras.initializers.GlorotUniform(seed=123))(x)
x=Dropout(rate=dropout, seed=123)(x)        
output=Dense(class_count, activation='softmax',kernel_initializer=tf.keras.initializers.GlorotUniform(seed=123))(x)
model=Model(inputs=base_model.input, outputs=output)
model.compile(Adamax(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) 
rlronp=tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=1, verbose=1, mode='auto', min_delta=0.0001, cooldown=0, min_lr=0)
estop=tf.keras.callbacks.EarlyStopping( monitor="val_loss", min_delta=0, patience=4,
                                       verbose=1,  mode="auto",  baseline=None,
                                        restore_best_weights=True)
callbacks=[rlronp, estop]
另外,请查看数据集中的余额。也就是说,比较每堂课有多少个训练样本。如果大多数样本/最少样本的比率>2或3,您可能需要采取措施来缓解这种情况。有许多方法可用,最简单的方法是在model.fit中使用class_weight参数。o要做到这一点,您需要创建一个类权重字典。下面概述了实现这一点的过程

Lets say your class distribution is
 class0 - 500 samples
 class1- 2000 samples
 class2 - 1500 samples
 class3 - 200 samples
Then your dictionary would be
class_weights={0: 2000/500, 1:2000/2000, 2: 2000/1500, 3: 2000/200}
in model.fit set class_weight=class_weights

我认为你对所需参数数量的估计有很大偏差。想想看,如果你使用迁移学习,你会得到几百万。如果你愿意,你可以努力尝试制作自己的模型,但你很可能不会比迁移学习的结果更好(而且更可能没有那么好)。我强烈推荐MobileV2型号。现在,如果使用ReducelRon平台的可调学习率,您可以使该模型或任何其他模型的性能更好。我建议的另一件事是使用Keras回调earlystoping。文件是。将其设置为监视验证丢失,并将restore\u best\u weights=True。将历元数设置为一个较大的数字,以便触发此回调并返回具有来自验证损失最低的历元的权重的模型。我推荐的代码如下所示

height=224
width=224
img_shape=(height, width, 3)
dropout=.3
lr=.001
class_count=156 # number of classes
img_shape=(height, width, 3)
base_model=tf.keras.applications.MobileNetV2( include_top=False, input_shape=img_shape, pooling='max', weights='imagenet') 
x=base_model.output
x=keras.layers.BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001 )(x)
x = Dense(512, kernel_regularizer = regularizers.l2(l = 0.016),activity_regularizer=regularizers.l1(0.006),
                bias_regularizer=regularizers.l1(0.006) ,activation='relu', kernel_initializer= tf.keras.initializers.GlorotUniform(seed=123))(x)
x=Dropout(rate=dropout, seed=123)(x)        
output=Dense(class_count, activation='softmax',kernel_initializer=tf.keras.initializers.GlorotUniform(seed=123))(x)
model=Model(inputs=base_model.input, outputs=output)
model.compile(Adamax(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) 
rlronp=tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=1, verbose=1, mode='auto', min_delta=0.0001, cooldown=0, min_lr=0)
estop=tf.keras.callbacks.EarlyStopping( monitor="val_loss", min_delta=0, patience=4,
                                       verbose=1,  mode="auto",  baseline=None,
                                        restore_best_weights=True)
callbacks=[rlronp, estop]
另外,请查看数据集中的余额。也就是说,比较每堂课有多少个训练样本。如果大多数样本/最少样本的比率>2或3,您可能需要采取措施来缓解这种情况。有许多方法可用,最简单的方法是在model.fit中使用class_weight参数。o要做到这一点,您需要创建一个类权重字典。下面概述了实现这一点的过程

Lets say your class distribution is
 class0 - 500 samples
 class1- 2000 samples
 class2 - 1500 samples
 class3 - 200 samples
Then your dictionary would be
class_weights={0: 2000/500, 1:2000/2000, 2: 2000/1500, 3: 2000/200}
in model.fit set class_weight=class_weights
专家们是如何设计CNN的?我如何在初始模块、退出正则化、批量规范化、卷积滤波器大小、卷积通道的大小和深度、完全连接层的数量、激活神经元等之间进行选择?人们如何以科学的方式处理这个大型优化问题?这种组合是无穷无尽的

你真的说过这些组合的数量很大。如果没有正确的接近,你可能会一事无成。一位伟人说机器学习是一门艺术,而不是科学。结果取决于数据。以下是一些关于您上述问题的提示

  • 记录所有内容:在训练时间内,保存每个实验的必要日志,如训练损失、验证损失、重量文件、执行时间、可视化等。其中一些日志可以使用
    CSVLogger
    保存,
    modelscheckpoint
    等。
    TensorBoard
    是检查培训日志和可视化以及更多功能的绝佳工具

  • 强验证策略:这非常重要。为了建立稳定的交叉验证(CV),我们必须充分了解数据和面临的挑战。我们将检查并确保验证集具有与训练集测试集相似的分布。我们将努力确保我们的模型在我们的CV测试集(如果测试集可用
    gt
    )上都得到改进。基本上,随机划分数据通常不足以满足这一要求。了解数据以及如何在不在简历中引入数据泄漏的情况下对其进行分区是避免过度拟合的关键

    class InceptionModule(tf.keras.layers.Layer):
        def __init__(self, kernel_size1x1, kernel_size3x3):
            super(InceptionModule, self).__init__()
            
            # two conv modules: they will take same input tensor 
            self.conv1 = ConvModule(kernel_size1x1, kernel_size=(1,1), strides=(1,1))
            self.conv2 = ConvModule(kernel_size3x3, kernel_size=(3,3), strides=(1,1))
            self.cat   = tf.keras.layers.Concatenate()
    
    
        def call(self, input_tensor, training=False):
            x_1x1 = self.conv1(input_tensor)
            x_3x3 = self.conv2(input_tensor)
            x = self.cat([x_1x1, x_3x3])
            return x 
    
  • 只更改一个:在实验过程中,一次更改一件事,并保存观察结果(
    日志
    )。例如:将图像大小从
    224
    (例如)逐渐更改为更大,然后观察结果。我们应该从一个小组合开始。在试验图像大小时,修复其他图像,如
    model
    archite
    class DownsampleModule(tf.keras.layers.Layer):
        def __init__(self, kernel_size):
            super(DownsampleModule, self).__init__()
    
            # conv layer
            self.conv3 = ConvModule(kernel_size, kernel_size=(3,3), 
                             strides=(2,2), padding="valid") 
    
            # pooling layer 
            self.pool  = tf.keras.layers.MaxPooling2D(pool_size=(3, 3), 
                             strides=(2,2))
            self.cat   = tf.keras.layers.Concatenate()
    
        def call(self, input_tensor, training=False):
            # forward pass 
            conv_x = self.conv3(input_tensor, training=training)
            pool_x = self.pool(input_tensor)
        
            # merged
            return self.cat([conv_x, pool_x])
    
    class MiniInception(tf.keras.Model):
        def __init__(self, num_classes=10):
            super(MiniInception, self).__init__()
    
            # the first conv module
            self.conv_block = ConvModule(96, (3,3), (1,1))
    
            # 2 inception module and 1 downsample module
            self.inception_block1  = InceptionModule(32, 32)
            self.inception_block2  = InceptionModule(32, 48)
            self.downsample_block1 = DownsampleModule(80)
      
            # 4 inception module and 1 downsample module
            self.inception_block3  = InceptionModule(112, 48)
            self.inception_block4  = InceptionModule(96, 64)
            self.inception_block5  = InceptionModule(80, 80)
            self.inception_block6  = InceptionModule(48, 96)
            self.downsample_block2 = DownsampleModule(96)
    
            # 2 inception module 
            self.inception_block7 = InceptionModule(176, 160)
            self.inception_block8 = InceptionModule(176, 160)
    
            # average pooling
            self.avg_pool = tf.keras.layers.AveragePooling2D((7,7))
    
            # model tail
            self.flat      = tf.keras.layers.Flatten()
            self.classfier = tf.keras.layers.Dense(num_classes, activation='softmax')
    
    
        def call(self, input_tensor, training=True, **kwargs):
            # forward pass 
            x = self.conv_block(input_tensor)
            x = self.inception_block1(x)
            x = self.inception_block2(x)
            x = self.downsample_block1(x)
    
            x = self.inception_block3(x)
            x = self.inception_block4(x)
            x = self.inception_block5(x)
            x = self.inception_block6(x)
            x = self.downsample_block2(x)
    
            x = self.inception_block7(x)
            x = self.inception_block8(x)
            x = self.avg_pool(x)
    
            x = self.flat(x)
            return self.classfier(x)