一个和图片一样大的卷积核可以学习到什么?

引子

超参数的定义是在开始学习过程之前设置值的参数,而不是通过训练得到的参数,包括模型结构,各种激活函数,学习率等等。

如果模型的超参数合适, 即使用简单的模型,网络也能够学到有趣的东西.

这个实验的初心是什么? 就是用尽量简洁的模型, 学习到尽量多的信息, 尤其可以视觉化呈现学习到的东西.


cnn模型可以大幅简化

看一个tensorflow官方的cnn模型 :     卷积神经网络(Convolutional Neural Network, CNN)  |  TensorFlow Core

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)                (None, 30, 30, 32)          896       
 max_pooling2d (MaxPooling2D)   (None, 15, 15, 32)            0         
 conv2d_1 (Conv2D)              (None, 13, 13, 64)        18496     
 max_pooling2d_1 (MaxPooling2D) (None, 6, 6, 64)              0         
 conv2d_2 (Conv2D)              (None, 4, 4, 64)          36928     
 flatten              (None, 1024)                  0         
 dense (Dense)                  (None, 64)                65600     
 dense_1 (Dense)                (None, 10)                  650  

这个模型有3个卷积层和2个全连接层, 用来学习mnist 有些大材小用. 如果简化去掉一些层,只剩下一个卷积层和一个展平层 (Flatten)加一个全连接层,  甚至仅仅用一个全连接层都能学到不少东西,达到95%以上的验证集正确率.


对cnn模型进行一些简化


 


1,   下图是超大卷积核的模型结构: 

一个卷积层+  一个展平层 (Flatten)+  一个全连接层

用100x 100的卷积核去卷28x 28的照片, 并且padding设置为same,卷积核在照片上滑动.

训练结果, 视觉化展示唯一的卷积核:

2,  与图片等大的16个 卷积核(28x 28 ).  模型结构: 

一个卷积层+  一个展平层 (Flatten)+  一个全连接层

一般来说卷积核要小于图片, 卷积核在图片上滑动来提取信息,相当于拍摄了多张照片.  如果采用等大卷积核,并且padding设置为valid ,这个超大卷积核就不再滑动, 相当于仅仅拍摄一张照片.

下图是在mnist 数据集上训练结果, 视觉化展示卷积核, 在第一个epoch 就学到了类似数字的图形, 但是有些混乱, 是数字叠加的影像.

 

 上图最右面, 可以看到从mnist中学习到了东西。但是叠加的影像,还不够清晰。


当时猜测原因有两个:

第一个是要将  sparse categorical cross entropy转换到categorical cross entropy,后来证明这个原因猜错了.

第二个是要去除展平层 (Flatten)和全连接层(FC), 每类数据不要交互,  这个猜对了. 果然学到了!!

 从上图可以看到,一些数字形状比如"0,1,2,5,7 "很好学习, 但是经过反复实验其它数字学不到.

然后猜测应该更换损失函数, 从relu 换到sigmoid,  成功 !!

在fashion_mnist数据集上也是成功的!

(支线任务,用小一点的卷积核,可以减少模型的参数)

下图 是23x 23  卷积核,将有少量的滑动,比不滑动效果更好:

 

 下图是 25x 25 卷积核,  有更少量的滑动,笔画似乎更细:

 

 

(支线任务,膨胀卷积核,可以获得更少的参数)

如果看不清就咪咪眼

 

突然想起来, 这样用卷积学到的分类别图像, 有点像英国科学家做的人种平均脸图像

# 更换模型的输入标签从spars cross entropy 到  cross entropy ,   # 更换最后一层,不要全连接



# 卷积 然后 展平, 再多对多, 完全打乱了信息, 不能够得到预先设想的  10个数字
#  todo  要是希望用10个超大卷积核对应10个数字,    算法结构中应该只有少量的 平移卷积, 没有多对多的全连接层



# todo 测试 数组转图片,然后画图的输入范围,是否能自动map数值的上下限,是否对负数自动变为正数
# todo 用2层卷积核,拟合数据, 然后在训练完成并训练结果较好的时候, 将2层卷积核相乘,看看每一种可能性 ,看看能不能看到 1-9-0 十个数字

#  todo 加入部件 输出gif 或者mp4

# todo  加入部件,看卷积核与fc层连接的权重

#  todo 卷积核的初始化很重要,  看到20x20的卷积核虽然测试及表现良好,但是学习的花纹有些看不懂,也许学习的很正确,但是人类看不懂.  希望构造部件学习到类似条纹的卷积核                         另外,看到20个epochs 后,花纹基本不变, 不过从初始化到第一步看不到. todo 加入部件,看最初的初始化.     

# todo 如何解包, 而不是将一堆小文件存储在文件夹里   --切片??




# 终于提取到卷积核的数据,  并且用图片形式表示出来(每个epoch 只画一个卷积核 ) , 并且画出全部卷积核
# https://blog.csdn.net/gaotihong/article/details/80983937      ---Python-matplotlib画图


# 控制 logs: [ p.terminate() for p in processes if p.is_alive()]

# 在model.Sequential. 里面 找卷积核数值

# xxxx  卷积核的位置从  print(model.summary())   可以获知, 每次运行 卷积核的序列号加2

# 可以用命名的方式,指定每层的名称。  from https://www.tensorflow.org/guide/keras/sequential_model

#  (因为每个层都是一个类,所以返回的层本质上是一个类)

#导入模块
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow import keras
from tensorflow.keras.callbacks import LambdaCallback   
from PIL import Image


################################################################
# 没有gpu的计算机不需要本段
# 这一段的作用是在用gpu计算时,debug gpu内存报错  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.
    #  [[node sequential/cnn_layer/Conv2D (defined at tmp/ipykernel_13733/2736373417.py:104) ]] [Op:__inference_distributed_function_799]
from tensorflow.compat.v1.keras.backend  import set_session
config=tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True 
sess=tf.compat.v1.Session(config=config) 
set_session(sess)
tf.keras.backend.clear_session() #清理session
###############################################################


#导入数据集
mnist = tf.keras.datasets.mnist
#mnist = tf.keras.datasets.fashion_mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()

#数据预处理
#Reshape
x_train4D = x_train.reshape(x_train.shape[0],28,28,1).astype('float32') 
x_test4D = x_test.reshape(x_test.shape[0],28,28,1).astype('float32') 
#像素标准化
x_train, x_test = x_train4D / 255.0, x_test4D / 255.0


#模型搭建
model = tf.keras.models.Sequential([
    # tf.keras.layers.Conv2D(filters=16 , kernel_size=(20,20), padding='VALID',input_shape=(28,28,1),  activation='relu',name="cnn_layer"),      #  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<卷积核大小  数量
    #tf.keras.layers.Conv2D(filters=16 , kernel_size=(28,28), padding='VALID',input_shape=(28,28,1),  activation='sigmoid',name="cnn_layer"),      #  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<卷积核大小  数量
    tf.keras.layers.Conv2D(filters=16 , kernel_size=(25,25), padding='VALID',input_shape=(28,28,1), dilation_rate=1,  activation='sigmoid',name="cnn_layer"),      #  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<卷积核大小  数量

    # VALID  valid
    tf.keras.layers.Flatten(),                                                                     #  卷积层输出二维数据,而全连接层接收一维数据,faltten降维数据
    #tf.keras.layers.Dense(10,activation='softmax')
    #tf.keras.layers.Dense(10,activation='sigmoid')             #   relu不行, 学不到东西.        sigmoid   ,  softmax  能够学到东西
    
])

 


#打印模型
print(model.summary())                 # print  模型

#训练配置
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam', metrics=['accuracy']) 


#开始训练
 


class plot_kernel(keras.callbacks.Callback):        #   定义class
    """
    def on_train_begin(self, logs={}):
        self.losses = []
    """

    def on_epoch_end(self, batch, logs={}):
        #img = Image.fromarray(model.get_layer(name="cnn_layer").kernel.numpy ()[:, :, :, :])

        plt.figure(figsize=(6, 6)) #设置窗口大小
        plt.suptitle('cnn_layer') # 图片名称
        
        for i in range(0,16 ):                                                                                                                                                                    #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  绘图 ,设定卷积核个数
            img = Image.fromarray(model.get_layer(name="cnn_layer").kernel.numpy ()[:,:,0,i]   *500+200   )
            plt.subplot(4,4,  (i+1)  ) 
            plt.title('  ')
            plt.imshow(img)
            #plt.axis('off')                  # plt.imshow(gray,cmap='gray'), plt.axis('off') #这里显示灰度图要加cmap
            plt.xticks([])            # 去除x轴刻度标记   ,可以用 plt.xticks(fontsize=0) 去除x轴刻度数字
            plt.yticks([])            # plt.yticks(fontsize=0)
            #        plt.axes.get_xaxis().set_visible(False)  #??
           #        plt..axes.get_yaxis().set_visible(False) #??
        plt.show()

        
        
        
pltKernel = plot_kernel()                              #  class 实例化



model.fit(
    x=x_train, y=y_train, 
    callbacks=[pltKernel], 
    validation_split=0.2, 
    epochs=50 , batch_size=300, verbose=2)   # verbose = 2 为每个epoch输出一行记录       <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,<<<                  epochs


#print("model.get_layer(index=0).output_shape============",    model.get_layer(index=0).output_shape)   #  这个是第一层(cnn)的输出图片.维度
print("model.cnn_layer.kernel=============",          model.get_layer(name="cnn_layer").kernel)    
print("model.cnn_layer.kernel.shape=========",        model.get_layer(name="cnn_layer").kernel.shape)    # 这个是第一层 卷积核图片.维度


# callbacks

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值