精华内容
下载资源
问答
  • 卷积神经网络实现图像识别及过程可视化

    万次阅读 多人点赞 2018-06-12 17:53:15
    本博文提供经典的卷积神经网络实现代码,将CNN的工具类等代码分别封装,并提供接口自行替换使用的模型(可以换成自己的神经网络及图片样本),代码中提供模型保存和读取,并对卷积层的计算结果反卷积还原成图片输出...

    卷积神经网络实现图像识别及过程可视化


    本博文提供经典的卷积神经网络实现代码,将CNN的工具类等代码分别封装,并提供接口自行替换使用的模型(可以换成自己的神经网络及图片样本),代码中提供模型保存和读取,并对卷积层的计算结果反卷积还原成图片输出到tensorboard中,最后可以在tensorboard中观察CNN训练的过程和结果数据,并查看过程中卷积核提取的具体特征。


    实验环境 i7-8750 + GTX 1066, tensorflow-gpu 1.80 + cuda 9 + cudnn 7 + anaconda3(python3.6.5)

    一、样本文件存储形式

    样本按照不同类别保存在不同文件夹中,每个文件夹代表一个类别,然后这些文件夹放在同一文件夹中,该文件夹和脚本同一目录下。
    这里写图片描述
    样本读取后记得要转换成 numpy.array 的格式,其中注意,为了能够输入tensorflow网络中,样本数据需要满足格式符合 tf.float32 格式,标签数据需要满足 tf.int32格式,这两个格式和numpy是兼容的,所以注意格式否则输入网络会报错。

    '''
    从path中读取图片文件
    文件存储方式:path - class1 - pic1.jpg ...
                       - class2 - picn.jpg ...
    '''
    def load_data(path,imgw,imgh):
        # 如果把文件夹目录下为文件下的路径加入集合
        classes = [path+x for x in os.listdir(path) if os.path.isdir(path+x)]
    
        imgs = []
        labels = []
    
        for label, folder in enumerate(classes):
            # 读取xxx/*.jpg
            for img in glob.glob(folder + '/*jpg'):
                img = io.imread(img)
                img = transform.resize(img,(imgw,imgh))
                imgs.append(img)
                labels.append(label)
        return np.asarray(imgs, dtype=np.float32), np.array(labels, dtype=np.int32) #记住labels一定要转换成int32形式

    二、其他样本处理

    ''' 
    样本打乱顺序
    '''
    def disrupt_order(data, labels):
        total_num = data.shape[0]
        order_arrlist = np.arange(total_num)
        random.shuffle(order_arrlist)
        data = data[order_arrlist]
        labels = labels[order_arrlist]
        return data , labels
    
    
    '''
    分割测试训练集
    '''
    def get_train_test_data(data, labels, percent):
        seg_point = int(data.shape[0] * percent)
    
        x_train = data[0:seg_point, :]
        x_test = data[seg_point:, :]
    
        y_train = labels[0:seg_point]
        y_test = labels[seg_point:]
    
        return x_train, y_train, x_test, y_test
    
    #定义一个函数,按批次取数据
    def minibatches(inputs=None, targets=None, batch_size=None, shuffle=False):
        assert len(inputs) == len(targets)
        if shuffle:
            indices = np.arange(len(inputs))
            np.random.shuffle(indices)
        for start_idx in range(0, len(inputs) - batch_size + 1, batch_size):
            if shuffle:
                excerpt = indices[start_idx:start_idx + batch_size]
            else:
                excerpt = slice(start_idx, start_idx + batch_size)
            yield inputs[excerpt], targets[excerpt]

    三、CNN模型代码

    def inference(input_tensor, train, regularizer):
        with tf.variable_scope('layer1-conv1'):
            conv1_weights = tf.get_variable("weight",[5,5,3,32],initializer=tf.truncated_normal_initializer(stddev=0.1))
            conv1_biases = tf.get_variable("bias", [32], initializer=tf.constant_initializer(0.0))
            conv1 = tf.nn.conv2d(input_tensor, conv1_weights, strides=[1, 1, 1, 1], padding='SAME')
            relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_biases))
    
        with tf.name_scope("layer2-pool1"):
            pool1 = tf.nn.max_pool(relu1, ksize = [1,2,2,1],strides=[1,2,2,1],padding="VALID")
    
        with tf.variable_scope("layer3-conv2"):
            conv2_weights = tf.get_variable("weight",[5,5,32,64],initializer=tf.truncated_normal_initializer(stddev=0.1))
            conv2_biases = tf.get_variable("bias", [64], initializer=tf.constant_initializer(0.0))
            conv2 = tf.nn.conv2d(pool1, conv2_weights, strides=[1, 1, 1, 1], padding='SAME')
            relu2 = tf.nn.relu(tf.nn.bias_add(conv2, conv2_biases))
    
        with tf.name_scope("layer4-pool2"):
            pool2 = tf.nn.max_pool(relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
    
        with tf.variable_scope("layer5-conv3"):
            conv3_weights = tf.get_variable("weight",[3,3,64,128],initializer=tf.truncated_normal_initializer(stddev=0.1))
            conv3_biases = tf.get_variable("bias", [128], initializer=tf.constant_initializer(0.0))
            conv3 = tf.nn.conv2d(pool2, conv3_weights, strides=[1, 1, 1, 1], padding='SAME')
            relu3 = tf.nn.relu(tf.nn.bias_add(conv3, conv3_biases))
    
        with tf.name_scope("layer6-pool3"):
            pool3 = tf.nn.max_pool(relu3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
    
        with tf.variable_scope("layer7-conv4"):
            conv4_weights = tf.get_variable("weight",[3,3,128,128],initializer=tf.truncated_normal_initializer(stddev=0.1))
            conv4_biases = tf.get_variable("bias", [128], initializer=tf.constant_initializer(0.0))
            conv4 = tf.nn.conv2d(pool3, conv4_weights, strides=[1, 1, 1, 1], padding='SAME')
            relu4 = tf.nn.relu(tf.nn.bias_add(conv4, conv4_biases))
    
        with tf.name_scope("layer8-pool4"):
            pool4 = tf.nn.max_pool(relu4, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
            nodes = 6*6*128
            reshaped = tf.reshape(pool4,[-1,nodes])
    
        with tf.variable_scope('layer9-fc1'):
            fc1_weights = tf.get_variable("weight", [nodes, 1024],
                                          initializer=tf.truncated_normal_initializer(stddev=0.1))
            if regularizer != None: tf.add_to_collection('losses', regularizer(fc1_weights))
            fc1_biases = tf.get_variable("bias", [1024], initializer=tf.constant_initializer(0.1))
    
            fc1 = tf.nn.relu(tf.matmul(reshaped, fc1_weights) + fc1_biases)
            if train: fc1 = tf.nn.dropout(fc1, 0.5)
    
        with tf.variable_scope('layer10-fc2'):
            fc2_weights = tf.get_variable("weight", [1024, 512],
                                          initializer=tf.truncated_normal_initializer(stddev=0.1))
            if regularizer != None: tf.add_to_collection('losses', regularizer(fc2_weights))
            fc2_biases = tf.get_variable("bias", [512], initializer=tf.constant_initializer(0.1))
    
            fc2 = tf.nn.relu(tf.matmul(fc1, fc2_weights) + fc2_biases)
            if train: fc2 = tf.nn.dropout(fc2, 0.5)
    
        with tf.variable_scope('layer11-fc3'):
            fc3_weights = tf.get_variable("weight", [512, 5],
                                          initializer=tf.truncated_normal_initializer(stddev=0.1))
            if regularizer != None: tf.add_to_collection('losses', regularizer(fc3_weights))
            fc3_biases = tf.get_variable("bias", [5], initializer=tf.constant_initializer(0.1))
            logit = tf.matmul(fc2, fc3_weights) + fc3_biases
    
        return logit
    

    注意这里需要手动计算卷积层到全连接层的数据维度,即计算reshape的参数。
    reshaped = tf.reshape(pool4,[-1,nodes])
    这里-1表示tensorflow自动计算数据维度,实际上-1处计算结果是样本总数,因此另一个参数是每个样本图像被多次卷积、池化后的结果数据拉长成一维之后总元素数目。例如计算得出每个样本图像为宽w高h深度d,这里就要填w*h*d。
    这里w,h,d在经过每个卷积层和池化层时都会发生变化。

    四、建立session训练模型

    为了方便训练和测试更换数据,使用feed_dict的字典方式。

    '''
    
    author : Fangtao
    
    该脚本读取path目录下的图片样本,处理后输入神经网络
    神经网络来源于脚本models.py,可以多个模型中选一个
    样本预处理函数保存在helpFunctions.py中
    过程中保存acc和卷积后的图片等信息,可以通过tensorboard可视化
    
    '''
    from skimage import io,transform
    # glob用于查找符合特定规则的路径名
    import glob
    import os
    import tensorflow as tf
    import numpy as np
    import time
    from helpFunctions import *
    from models import *
    
    path = 'flower_photos/'
    model_saved_path = 'ckpt/model.ckpt'
    w = 100
    h = 100
    
    print("loading files...")
    data, labels = load_data(path, w ,h)
    print('files loaded')
    
    total_num = data.shape[0]
    
    '''打乱样本,分散不同样本顺序'''
    data , labels = disrupt_order(data , labels)
    
    '''分割数据集'''
    x_train, y_train, x_test, y_test = get_train_test_data(data, labels, 0.8)
    
    
    print('train data size:',x_train.shape)
    print('train label size:',y_train.shape)
    #
    x = tf.placeholder(dtype=tf.float32, shape=[None, w, h, 3],name='x')
    y = tf.placeholder(dtype=tf.int32, shape=[None,],name='y')
    
    regulizer = tf.contrib.layers.l2_regularizer(0.0001)
    
    # 数据流一遍通过网络计算输出
    # output = AlexNet(x, True, regulizer, 5)
    output = inference(x, True, regulizer)
    
    #(小处理)将logits乘以1赋值给logits_eval,定义name,方便在后续调用模型时通过tensor名字调用输出tensor
    b = tf.constant(value=1,dtype=tf.float32)
    logits_eval = tf.multiply(output,b,name='logits_eval')
    
    # 计算损失(多分类softmax)
    loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=output, labels=y)
    
    #
    '''
    使用优化器减小损失
    如果acc一直上不去,很可能是lr设置太大,导致无法收敛到合理的最优解
    '''
    optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
    
    '''
    计算正确率
    先计算出每行output最大值,也就是最可能的预测label,用arg_max
    为了和y比较,要cast成相同类型数据,tf.int32
    然后和y比较相同数据,用equals
    最后reduce_meam计算下平均对了几个,在这之前还要cast成float32类型才能计算平均值
    '''
    with tf.name_scope('loss'):
        acc = tf.reduce_mean(tf.cast(tf.equal(tf.cast(tf.arg_max(output,1),dtype=tf.int32),y),tf.float32))
        tf.summary.scalar('accuracy',acc)  # tfboard一维常量可以放进summary显示图表
    
    n_epoch = 1
    batch_size=64
    saver = tf.train.Saver()
    sess = tf.Session()
    
    '''tensorboard 可视化'''
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter('DeskTop/',sess.graph)
    
    ''' 如果加载以前的网络 '''
    saver = tf.train.import_meta_graph('ckpt/model.ckpt.meta')  # 加载网络结构
    saver.restore(sess, tf.train.latest_checkpoint("ckpt/"))  # 加载检查点
    
    ''' 不加载就随机初始化'''
    # sess.run(tf.global_variables_initializer())
    
    '''
    每批次都先训练,再测试
    训练和测试都分成小批次
    每批训练完后都保存
    '''
    for epoch in range(n_epoch):
        start_time = time.time()
        #training
        train_loss, train_acc, n_batch = 0, 0, 0
        for x_train_batch, y_train_batch in minibatches(x_train, y_train, batch_size, shuffle=True):
            _,err,ac=sess.run([optimizer,loss,acc], feed_dict={x: x_train_batch, y: y_train_batch})  # 注意这里一定要一批一批的放!!!放多了维度不对conv2d他妈的竟然报错我日老子找了俩小时
    
            train_loss += err
            train_acc += ac
            n_batch += 1
        print("   train loss: %f" % (np.sum(train_loss) / n_batch))
        print("   train acc: %f" % (np.sum(train_acc) / n_batch))
    
    
        test_acc, test_loss, n_batch = 0, 0, 0
        for x_test_batch, y_test_batch in minibatches(x_test , y_test, batch_size,shuffle=False):   # 测试时不需要打乱
            err, ac = sess.run([loss, acc], feed_dict={x : x_test_batch, y : y_test_batch })
            test_loss += err
            test_acc += ac
            n_batch += 1
    
            '''
            这两句是绘制折线图等图表的
            把每次训练过程中的变量数值加到summary当中最后绘制
            如果训练中一个变量都不加进来的话就会报错:None
            '''
            result = sess.run(merged, feed_dict={x: x_train_batch, y: y_train_batch})  # merged也是需要run的
            writer.add_summary(result,epoch)  # result是summary类型的,需要放入writer中,i步数(x轴)
    
        print("   test loss: %f" % (np.sum(test_loss) / n_batch))
        print("   test acc: %f" % (np.sum(test_acc) / n_batch))
        saver.save(sess,model_saved_path)
    sess.close()
    '''可视化comda prompt里面调用这句:tensorboard --logdir D:\代码\BaoyanLearn\Desktop '''

    笔者一开始训练的时候发现同样的模型下我的正确率一直徘徊在26%左右,而他人的则是60~70%左右,后来发现是learning_rate少打了个0 。=-=因此学习率设置的足够小才能够保证结果不在最优解过远处徘徊(无法收敛到最优解),但过小的正确率又会导致训练速度过慢的问题。
    此外输入网络模型的时候一定要注意好数据shape的问题,有问题过程中把shape打印出来有利于快速定位哪里的张量出了问题。另外注意样本最好一批一批的放进去。如果输入feed_dict中的x和y样本数目不符合要求,可能会在loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=output, labels=y) 这一句报错。

    另外训练之前要注意,初次训练需要调用sess.run(tf.global_variables_initializer())函数初始化所有weight和bias的数据(随机初始化),然后才能进行接下来的训练。当训练几十次后保存checkpoint,下次想要接着训练或直接用于分类任务时,只需要调用
    saver = tf.train.import_meta_graph('ckpt/model.ckpt.meta') # 加载网络结构
    saver.restore(sess, tf.train.latest_checkpoint("ckpt/")) # 加载检查点

    两句话加载网络结构和内部权重即可,不需要再调用初始化语句sess.run(tf.global_variables_initializer())(这句话在调用就相当于没有加载以前训练好的权重数据了)。权重数据被保存在ckpt文件夹下。
    然后模型的保存:

    五、训练中tensorboard可视化

    训练过程中调整参数调整模型时,我们需要对训练中的accuracy、loss、weights等参数的变化有个整体的把握,最好能够把模型的整体框架绘成图,把每一步卷积核的效果可视化,方便找出难以提升准确率等的问题所在。这里用tensorflow自带的tensorboard做可视化。
    (1) 对过程中的weights等变量保存,用于绘制图表:

            tf.summary.histogram('convolution1' + "/weight", conv1_weight)
            tf.summary.histogram('convolution1' + "/bias", conv1_bias)

    这两句话执行在第一层卷积计算过后
    (2)对过程中训练后的accuracy保存绘制图表:

        tf.summary.scalar('accuracy',acc)  # tfboard一维常量可以放进summary显示图表

    这里注意要放进去的向量好像不能是张量,因为她要用来绘制折线图等。
    (3)可视化过程输出
    对过程中卷积计算的结果不能直接绘制成二维图像,要经历一个反卷积的过程才能输出一个原图像卷积后的图像,具体就是对当前数据反池化(如果有经过池化层的话,就需要补零),反激活(relu不怎么需要反激活),反卷积(把原先的卷积核再乘一遍),最终回到原始图像大小即可。
    第一层卷积层的输出反卷积:

            deconv = tf.nn.conv2d_transpose(relu1, conv1_weights, [64, 100, 100, 3],strides=[1, 1, 1, 1], padding='SAME')
            tf.summary.image('conv1_out', deconv, 10)

    第二层卷积层的输出反卷积(注意需要先经历第二层的卷积核的反卷积,在经历第一层的卷积核的反卷积才能得到和输入图像一直尺寸的输出):

            deconv2 = tf.nn.conv2d_transpose(relu2, conv2_weights, [64, 50, 50, 32],strides=[1, 1, 1, 1], padding='SAME')
            deconv2_ = tf.nn.conv2d_transpose(deconv2, conv1_weights, [64, 50, 50, 3], strides=[1, 1, 1, 1], padding='SAME')
            tf.summary.image('conv2_out', deconv2_, 10)
    

    最终可以在tensorboard中查看这些图表。查看时需要在anaconda prompt窗口下输入
    tensorboard --logdir 你的保存路径
    然后在命令行窗口中会返回一个网址,直接输入浏览器就能打开:
    原图效果:
    这里写图片描述
    两层卷积后效果:
    这里写图片描述

    六、测试脚本

    这个测试脚本可以用于测试数据集分类效果,也可以直接上线使用(比如让用户上传图片然后返回分类结果)。

    from skimage import io,transform
    # glob用于查找符合特定规则的路径名
    import glob
    import os
    import tensorflow as tf
    import numpy as np
    import time
    from helpFunctions import *
    from models import *
    
    path = 'test_pics/'
    model_saved_path = 'ckpt/model.ckpt.meta'
    
    w = 100
    h = 100
    
    print("loading files...")
    data, labels = load_data(path, w ,h)
    print('files loaded')
    
    total_num = data.shape[0]
    
    '''打乱样本,分散不同样本顺序'''
    data , labels = disrupt_order(data , labels)
    
    print('train data size:',data.shape)
    print('train label size:',labels.shape)
    #
    x = tf.placeholder(dtype=tf.float32, shape=[None, w, h, 3],name='x')
    y = tf.placeholder(dtype=tf.int32, shape=[None,],name='y')
    
    regulizer = tf.contrib.layers.l2_regularizer(0.0001)
    
    # 数据流一遍通过网络计算输出
    # output = AlexNet(x, True, regulizer, 5)
    output = inference(x, True, regulizer)
    
    #(小处理)将logits乘以1赋值给logits_eval,定义name,方便在后续调用模型时通过tensor名字调用输出tensor
    b = tf.constant(value=1,dtype=tf.float32)
    logits_eval = tf.multiply(output,b,name='logits_eval')
    
    # 计算损失(多分类softmax)
    loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=output, labels=y)
    
    #
    '''
    使用优化器减小损失
    如果acc一直上不去,很可能是lr设置太大,导致无法收敛到合理的最优解
    '''
    optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
    
    '''
    计算正确率
    先计算出每行output最大值,也就是最可能的预测label,用arg_max
    为了和y比较,要cast成相同类型数据,tf.int32
    然后和y比较相同数据,用equals
    最后reduce_meam计算下平均对了几个,在这之前还要cast成float32类型才能计算平均值
    '''
    with tf.name_scope('loss'):
        acc = tf.reduce_mean(tf.cast(tf.equal(tf.cast(tf.arg_max(output,1),dtype=tf.int32),y),tf.float32))
        tf.summary.scalar('accuracy1',acc)  # tfboard一维常量可以放进summary显示图表
    
    n_epoch = 1
    batch_size=1
    saver = tf.train.Saver()
    sess = tf.Session()
    
    saver = tf.train.import_meta_graph(model_saved_path)  # 加载网络结构
    saver.restore(sess, tf.train.latest_checkpoint("ckpt/"))  # 加载检查点
    
    '''tensorboard 可视化'''
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter('DeskTop/',sess.graph)
    
    '''
    每批次都先训练,再测试
    训练和测试都分成小批次
    每批训练完后都保存
    '''
    for epoch in range(n_epoch):
        out , err, ac = sess.run([output, loss, acc], feed_dict={x : data, y : labels })
    
        print('predicted:', out)
    sess.close()

    本文借鉴的博文有:
    tensorboard可视化
    TensorFlow之CNN图像分类及模型保存与调用
    tensorflow 1.0 学习:用CNN进行图像分类

    展开全文
  •  传统的CNN网络只能给出图像的LABLE,但是在很多情况下需要对识别的物体进行分割实现end to end,然后FCN出现了,给物体分割提供了一个非常重要的解决思路,其核心就是卷积与反卷积,所以这里就详细解释卷积与...

    1.前言

       传统的CNN网络只能给出图像的LABLE,但是在很多情况下需要对识别的物体进行分割实现end to end,然后FCN出现了,给物体分割提供了一个非常重要的解决思路,其核心就是卷积与反卷积,所以这里就详细解释卷积与反卷积。

        对于1维的卷积,公式(离散)与计算过程(连续)如下,要记住的是其中一个函数(原函数或者卷积函数)在卷积前要翻转180度

    图1

        对于离散卷积,f的大小是n1,g的大小是n2,卷积后的大小是n1+n2-1

    2.图像卷积

    图2

    同样地,卷积的时候需要对卷积核进行180的旋转,同时卷积核中心与需计算的图像像素对齐,输出结构为中心对齐像素的一个新的像素值,计算例子如下

    图3

    这样计算出左上角(即第一行第一列)像素的卷积后像素值。

     

    给出一个更直观的例子,从左到右看,原像素经过卷积由1变成-8。

    图4

    在信号处理上,反转180度称作卷积,直接滑动计算称作自相关,在大部分深度学习框架上都没有反转180度的操作。

    通过滑动卷积核,就可以得到整张图片的卷积结果,

    图5

        到了这里,大致可以明白图像卷积。但是我们可以看出,通过图像卷积后,新图像的大小跟原来一样,或者变小。图2计算后图像大小不变,如图5卷积后图像变小是因为没有对所用像素进行卷积计算。但是1维的卷积结果不是变大了吗? 下面对其解释。

     

        在matlb中对2维卷积的计算分为了3类,1.full   2.same   3. valid   参考:https://cn.mathworks.com/help/matlab/ref/conv2.html?requestedDomain=www.mathworks.com

    图2对应的卷积就是就是所谓的same,图5对应的就是valid。那么full又是什么呢?如下图

    图6

        图6中蓝色为原图像,白色为对应卷积所增加的padding,通常全部为0,绿色是卷积后图片。图6的卷积的滑动是从卷积核右下角与图片左上角重叠开始进行卷积,滑动步长为1,卷积核的中心元素对应卷积后图像的像素点。可以看到卷积后的图像是4X4,比原图2X2大了,我们还记1维卷积大小是n1+n2-1,这里原图是2X2,卷积核3X3,卷积后结果是4X4,与一维完全对应起来了。其实这才是完整的卷积计算,其他比它小的卷积结果都是省去了部分像素的卷积。下面是WIKI对应图像卷积后多出部分的解释:

    Kernel convolution usually requires values from pixels outside of the image boundaries. There are a variety of methods for handling image edges.意思就是多出来的部分根据实际情况可以有不同的处理方法。(其实这里的full卷积就是后面要说的反卷积)

     

    这里,我们可以总结出full,same,valid三种卷积后图像大小的计算公式:

    1.full: 滑动步长为1,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:N1+N2-1 x N1+N2-1

    如图6, 滑动步长为1,图片大小为2x2,卷积核大小为3x3,卷积后图像大小:4x4

    2.same: 滑动步长为1,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:N1xN1

    3.valid:滑动步长为S,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:(N1-N2)/S+1 x (N1-N2)/S+1

    如图5,滑动步长为1,图片大小为5x5,卷积核大小为3x3,卷积后图像大小:3x3

     

    3.反卷积(后卷积,转置卷积)

        这里提到的反卷积跟1维信号处理的反卷积计算是很不一样的,FCN作者称为backwards convolution,有人称Deconvolution layer is a very unfortunate name and should rather be called a transposed convolutional layer. 我们可以知道,在CNN中有con layer与pool layer,con layer进行对图像卷积提取特征,pool layer对图像缩小一半筛选重要特征,对于经典的图像识别CNN网络,如IMAGENET,最后输出结果是1X1X1000,1000是类别种类,1x1得到的是。FCN作者,或者后来对end to end研究的人员,就是对最终1x1的结果使用反卷积(事实上FCN作者最后的输出不是1X1,是图片大小的32分之一,但不影响反卷积的使用)。

        这里图像的反卷积与图6的full卷积原理是一样的,使用了这一种反卷积手段使得图像可以变大,FCN作者使用的方法是这里所说反卷积的一种变体,这样就可以获得相应的像素值,图像可以实现end to end。

    图7

        这里说另外一种反卷积做法,假设原图是3X3,首先使用上采样让图像变成7X7,可以看到图像多了很多空白的像素点。使用一个3X3的卷积核对图像进行滑动步长为1的valid卷积,得到一个5X5的图像,我们知道的是使用上采样扩大图片,使用反卷积填充图像内容,使得图像内容变得丰富,这也是CNN输出end to end结果的一种方法。韩国作者Hyeonwoo Noh使用VGG16层CNN网络后面加上对称的16层反卷积与上采样网络实现end to end 输出,其不同层上采样与反卷积变化效果如下,

                                                                                                                                                       图8

     

        到这里就把图像卷积与反卷积解释完成,如有不妥,请学者们指证。
       
        补充一个资料:
        图6与图7出处,https://github.com/vdumoulin/conv_arithmetic    

    ------------新增反卷积过程解释----------------
    经过上面的解释与推导,对卷积有基本的了解,但是在图像上的deconvolution究竟是怎么一回事,可能还是不能够很好的理解,因此这里再对这个过程解释一下。
    目前使用得最多的deconvolution有2种,上文都已经介绍。
    方法1:full卷积, 完整的卷积可以使得原来的定义域变大
    方法2:记录pooling index,然后扩大空间,再用卷积填充


    图像的deconvolution过程如下,

    输入:2x2, 卷积核:4x4, 滑动步长:3, 输出:7x7
    即输入为2x2的图片经过4x4的卷积核进行步长为3的反卷积的过程
    1.输入图片每个像素进行一次full卷积,根据full卷积大小计算可以知道每个像素的卷积后大小为 1+4-1=4, 即4x4大小的特征图,输入有4个像素所以4个4x4的特征图
    2.将4个特征图进行步长为3的fusion(即相加); 例如红色的特征图仍然是在原来输入位置(左上角),绿色还是在原来的位置(右上角),步长为3是指每隔3个像素进行fusion,重叠部分进行相加,即输出的第1行第4列是由红色特阵图的第一行第四列与绿色特征图的第一行第一列相加得到,其他如此类推。

    可以看出翻卷积的大小是由卷积核大小与滑动步长决定, in是输入大小, k是卷积核大小, s是滑动步长, out是输出大小
    得到 out = (in - 1) * s + k
    上图过程就是, (2 - 1) * 3 + 4 = 7
     

    展开全文
  • 传统的CNN网络只能给出图像的LABLE,但是在很多情况下需要对识别的物体进行分割实现end to end,然后FCN出现了,给物体分割提供了一个非常重要的解决思路,其核心就是卷积与反卷积,所以这里就详细解释卷积与反卷积...

    在这里插入图片描述

    1.前言

    传统的CNN网络只能给出图像的LABLE,但是在很多情况下需要对识别的物体进行分割实现end to end,然后FCN出现了,给物体分割提供了一个非常重要的解决思路,其核心就是卷积与反卷积,所以这里就详细解释卷积与反卷积。

    对于1维的卷积,公式(离散)与计算过程(连续)如下,要记住的是其中一个函数(原函数或者卷积函数)在卷积前要翻转180度

    在这里插入图片描述
    在这里插入图片描述
    图一

    对于离散卷积,f的大小是n1,g的大小是n2,卷积后的大小是n1+n2-1
    

    2.图像卷积

    图2
    图二
    同样地,卷积的时候需要对卷积核进行180的旋转,同时卷积核中心与需计算的图像像素对齐,输出结构为中心对齐像素的一个新的像素值,计算例子如下
    在这里插入图片描述
    图三

    这样计算出左上角(即第一行第一列)像素的卷积后像素值。

    给出一个更直观的例子,从左到右看,原像素经过卷积由1变成-8。

    图4
    图四
    在信号处理上,反转180度称作卷积,直接滑动计算称作自相关,在大部分深度学习框架上都没有反转180度的操作。

    通过滑动卷积核,就可以得到整张图片的卷积结果,

    图5
    图五
    到了这里,大致可以明白图像卷积。但是我们可以看出,通过图像卷积后,新图像的大小跟原来一样,或者变小。图2计算后图像大小不变,如图5卷积后图像变小是因为没有对所用像素进行卷积计算。但是1维的卷积结果不是变大了吗? 下面对其解释。

    在matlb中对2维卷积的计算分为了3类,1.full 2.same 3. valid
    参考:https://cn.mathworks.com/help/matlab/ref/conv2.html?requestedDomain=www.mathworks.com

    图2对应的卷积就是就是所谓的same,图5对应的就是valid。那么full又是什么呢?如下图

    图6
    图六
    上图中蓝色为原图像,白色为对应卷积所增加的padding,通常全部为0,绿色是卷积后图片。图6的卷积的滑动是从卷积核右下角与图片左上角重叠开始进行卷积,滑动步长为1,卷积核的中心元素对应卷积后图像的像素点。可以看到卷积后的图像是4X4,比原图2X2大了,我们还记1维卷积大小是n1+n2-1,这里原图是2X2,卷积核3X3,卷积后结果是4X4,与一维完全对应起来了。其实这才是完整的卷积计算,其他比它小的卷积结果都是省去了部分像素的卷积。下面是WIKI对应图像卷积后多出部分的解释:

    Kernel convolution usually requires values from pixels outside of the
    image boundaries. There are a variety of methods for handling image
    edges.意思就是多出来的部分根据实际情况可以有不同的处理方法。(其实这里的full卷积就是后面要说的反卷积)

    这里,我们可以总结出full,same,valid三种卷积后图像大小的计算公式:

    1.full: 滑动步长为1,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:N1+N2-1 x N1+N2-1

    如图6, 滑动步长为1,图片大小为2x2,卷积核大小为3x3,卷积后图像大小:4x4

    2.same: 滑动步长为1,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:N1xN1

    3.valid:滑动步长为S,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:(N1-N2)/S+1 x (N1-N2)/S+1

    如图5,滑动步长为1,图片大小为5x5,卷积核大小为3x3,卷积后图像大小:3x3

    3.反卷积(后卷积,转置卷积)
    这里提到的反卷积跟1维信号处理的反卷积计算是很不一样的,FCN作者称为backwards convolution,有人称Deconvolution layer is a very unfortunate name and should rather be called a transposed convolutional layer. 我们可以知道,在CNN中有con layer与pool layer,con layer进行对图像卷积提取特征,pool layer对图像缩小一半筛选重要特征,对于经典的图像识别CNN网络,如IMAGENET,最后输出结果是1X1X1000,1000是类别种类,1x1得到的是。FCN作者,或者后来对end to end研究的人员,就是对最终1x1的结果使用反卷积(事实上FCN作者最后的输出不是1X1,是图片大小的32分之一,但不影响反卷积的使用)。

    这里图像的反卷积与图6的full卷积原理是一样的,使用了这一种反卷积手段使得图像可以变大,FCN作者使用的方法是这里所说反卷积的一种变体,这样就可以获得相应的像素值,图像可以实现end to end。

    在这里插入图片描述
    图7

    这里说另外一种反卷积做法,假设原图是3X3,首先使用上采样让图像变成7X7,可以看到图像多了很多空白的像素点。使用一个3X3的卷积核对图像进行滑动步长为1的valid卷积,得到一个5X5的图像,我们知道的是使用上采样扩大图片,使用反卷积填充图像内容,使得图像内容变得丰富,这也是CNN输出end to end结果的一种方法。韩国作者Hyeonwoo Noh使用VGG16层CNN网络后面加上对称的16层反卷积与上采样网络实现end to end 输出,其不同层上采样与反卷积变化效果如下,

    在这里插入图片描述
    图8

    到这里就把图像卷积与反卷积解释完成,如有不妥,请学者们指证。

    补充一个资料:
    图6与图7出处,https://github.com/vdumoulin/conv_arithmetic    
    

    ------------新增反卷积过程解释----------------
    经过上面的解释与推导,对卷积有基本的了解,但是在图像上的deconvolution究竟是怎么一回事,可能还是不能够很好的理解,因此这里再对这个过程解释一下。
    目前使用得最多的deconvolution有2种,上文都已经介绍。

    方法1:full卷积, 完整的卷积可以使得原来的定义域变大 方法
    2:记录pooling index,然后扩大空间,再用卷积填充

    图像的deconvolution过程如下,
    在这里插入图片描述

    输入:2x2, 卷积核:4x4, 滑动步长:3, 输出:7x7
    即输入为2x2的图片经过4x4的卷积核进行步长为3的反卷积的过程
    1.输入图片每个像素进行一次full卷积,根据full卷积大小计算可以知道每个像素的卷积后大小为 1+4-1=4, 即4x4大小的特征图,输入有4个像素所以4个4x4的特征图
    2.将4个特征图进行步长为3的fusion(即相加); 例如红色的特征图仍然是在原来输入位置(左上角),绿色还是在原来的位置(右上角),步长为3是指每隔3个像素进行fusion,重叠部分进行相加,即输出的第1行第4列是由红色特阵图的第一行第四列与绿色特征图的第一行第一列相加得到,其他如此类推。

    可以看出翻卷积的大小是由卷积核大小与滑动步长决定, in是输入大小, k是卷积核大小, s是滑动步长, out是输出大小
    得到 out = (in - 1) * s + k
    上图过程就是, (2 - 1) * 3 + 4 = 7

    展开全文
  • 转自:卷积神经网络CNN(1)——图像卷积与反卷积(后卷积,转置卷积)动态图1.前言   传统的CNN网络只能给出图像的LABLE,但是在很多情况下需要对识别的物体进行分割实现end to end,然后FCN...

    转自:卷积神经网络CNN(1)——图像卷积与反卷积(后卷积,转置卷积)

    1.前言

       传统的CNN网络只能给出图像的LABLE,但是在很多情况下需要对识别的物体进行分割实现end to end,然后FCN出现了,给物体分割提供了一个非常重要的解决思路,其核心就是卷积与反卷积,所以这里就详细解释卷积与反卷积。
        对于1维的卷积,公式(离散)与计算过程(连续)如下,要记住的是其中一个函数(原函数或者卷积函数)在卷积前要翻转180度

    图1
        对于离散卷积,f的大小是n1,g的大小是n2,卷积后的大小是n1+n2-1

    2.图像卷积


    图2
    同样地,卷积的时候需要对卷积核进行180的旋转,同时卷积核中心与需计算的图像像素对齐,输出结构为中心对齐像素的一个新的像素值,计算例子如下

    图3
    这样计算出左上角(即第一行第一列)像素的卷积后像素值。

    给出一个更直观的例子,从左到右看,原像素经过卷积由1变成-8。

    图4
    通过滑动卷积核,就可以得到整张图片的卷积结果,

    图5
        到了这里,大致可以明白图像卷积。但是我们可以看出,通过图像卷积后,新图像的大小跟原来一样,或者变小。图2计算后图像大小不变,如图5卷积后图像变小是因为没有对所用像素进行卷积计算。但是1维的卷积结果不是变大了吗? 下面对其解释。

        在matlb中对2维卷积的计算分为了3类,1.full   2.same   3. valid   参考:https://cn.mathworks.com/help/matlab/ref/conv2.html?requestedDomain=www.mathworks.com
    图2对应的卷积就是就是所谓的same,图5对应的就是valid。那么full又是什么呢?如下图

    图6

        图6中蓝色为原图像,白色为对应卷积所增加的padding,通常全部为0,绿色是卷积后图片。图6的卷积的滑动是从卷积核右下角与图片左上角重叠开始进行卷积,滑动步长为1,卷积核的中心元素对应卷积后图像的像素点。可以看到卷积后的图像是4X4,比原图2X2大了,我们还记1维卷积大小是n1+n2-1,这里原图是2X2,卷积核3X3,卷积后结果是4X4,与一维完全对应起来了。其实这才是完整的卷积计算,其他比它小的卷积结果都是省去了部分像素的卷积。下面是WIKI对应图像卷积后多出部分的解释:

    Kernel convolution usually requires values from pixels outside of the image boundaries. There are a variety of methods for handling image edges.意思就是多出来的部分根据实际情况可以有不同的处理方法。(其实这里的full卷积就是后面要说的反卷积)


    这里,我们可以总结出full,same,valid三种卷积后图像大小的计算公式:
    1.full: 滑动步长为1,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:N1+N2-1 x N1+N2-1
    如图6, 滑动步长为1,图片大小为2x2,卷积核大小为3x3,卷积后图像大小:4x4
    2.same: 滑动步长为1,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:N1xN1
    3.valid:滑动步长为S,图片大小为N1xN1,卷积核大小为N2xN2,卷积后图像大小:(N1-N2)/S+1 x (N1-N2)/S+1
    如图5,滑动步长为1,图片大小为5x5,卷积核大小为3x3,卷积后图像大小:3x3

    3.反卷积(后卷积,转置卷积)

        这里提到的反卷积跟1维信号处理的反卷积计算是很不一样的,FCN作者称为backwards convolution,有人称Deconvolution layer is a very unfortunate name and should rather be called a transposed convolutional layer. 我们可以知道,在CNN中有con layer与pool layer,con layer进行对图像卷积提取特征,pool layer对图像缩小一半筛选重要特征,对于经典的图像识别CNN网络,如IMAGENET,最后输出结果是1X1X1000,1000是类别种类,1x1得到的是。FCN作者,或者后来对end to end研究的人员,就是对最终1x1的结果使用反卷积(事实上FCN作者最后的输出不是1X1,是图片大小的32分之一,但不影响反卷积的使用)。
        这里图像的反卷积与图6的full卷积原理是一样的,使用了这一种反卷积手段使得图像可以变大,FCN作者使用的方法是这里所说反卷积的一种变体,这样就可以获得相应的像素值,图像可以实现end to end。

    图7
        这里说另外一种反卷积做法,假设原图是3X3,首先使用上采样让图像变成7X7,可以看到图像多了很多空白的像素点。使用一个3X3的卷积核对图像进行滑动步长为1的valid卷积,得到一个5X5的图像,我们知道的是使用上采样扩大图片,使用反卷积填充图像内容,使得图像内容变得丰富,这也是CNN输出end to end结果的一种方法。韩国作者Hyeonwoo Noh使用VGG16层CNN网络后面加上对称的16层反卷积与上采样网络实现end to end 输出,其不同层上采样与反卷积变化效果如下,

                                                                                                                                                       图8

        到这里就把图像卷积与反卷积解释完成,如有不妥,请学者们指证。
        
        补充一个资料:
        图6与图7出处,https://github.com/vdumoulin/conv_arithmetic     

    ------------新增反卷积过程解释----------------
    经过上面的解释与推导,对卷积有基本的了解,但是在图像上的deconvolution究竟是怎么一回事,可能还是不能够很好的理解,因此这里再对这个过程解释一下。
    目前使用得最多的deconvolution有2种,上文都已经介绍。 
    方法1:full卷积, 完整的卷积可以使得原来的定义域变大
    方法2:记录pooling index,然后扩大空间,再用卷积填充

    图像的deconvolution过程如下,

    输入:2x2, 卷积核:4x4, 滑动步长:3, 输出:7x7
    即输入为2x2的图片经过4x4的卷积核进行步长为3的反卷积的过程
    1.输入图片每个像素进行一次full卷积,根据full卷积大小计算可以知道每个像素的卷积后大小为 1+4-1=4, 即4x4大小的特征图,输入有4个像素所以4个4x4的特征图
    2.将4个特征图进行步长为3的fusion(即相加); 例如红色的特征图仍然是在原来输入位置(左上角),绿色还是在原来的位置(右上角),步长为3是指每隔3个像素进行fusion,重叠部分进行相加,即输出的第1行第4列是由红色特阵图的第一行第四列与绿色特征图的第一行第一列相加得到,其他如此类推。

    可以看出反卷积的大小是由卷积核大小与滑动步长决定, in是输入大小, k是卷积核大小, s是滑动步长, out是输出大小
    得到 out = (in - 1) * s + k
    上图过程就是, (2 - 1) * 3 + 4 = 7
    展开全文
  • 传统的CNN网络只能给出图像的LABLE,但是在很多情况下需要对识别的物体进行分割实现end to end,然后FCN出现了,给物体分割提供了一个非常重要的解决思路,其核心就是卷积与反卷积,所以这里就详细解释卷积与反卷积...
  • 一文搞定卷积神经网络——从原理到应用

    万次阅读 多人点赞 2019-01-07 19:40:20
    文章目录1. 前言2. 全连接BP神经网络的缺点3. 卷积神经网络基本单元3.1 卷积(Convolution)3.2 ... 卷积神经网络的反向传播过程5.1 卷积层的误差传5.2 池化层的误差传6. 代码实现6.1 Numpy实现6.1.1 卷积层前...
  • 基于卷积神经网络的图像语义分割

    万次阅读 2018-02-14 20:37:03
    论文地址基于卷积神经网络的图像语义分割浙江大学硕士论文图像分割...1.分析了卷积神经网络在图像语义分割的应用前景,实现基于卷积神经网络和反卷积神经网络相结合的图像语义分割模型。2.对基于卷积神经网...
  • CNN卷积神经网络误差传推导

    千次阅读 2017-09-22 00:09:31
    CNN卷积神经网络推导和实现 zouxy09@qq.com http://blog.csdn.net/zouxy09 http://blog.csdn.net/zouxy09/article/details/9993371    自己平时看了一些论文,但老感觉看完过后就会慢慢的淡忘,某一...
  • 一.卷积 在深度学习的过程中,很多神经网络都会用到各种卷积核来进行操作,...而卷积神经网络的出现解决了这个问题,通过对一个局部区域进行卷积操作得到这个局部区域的特征值传入下层大大提升了神经网络提取特征...
  • CNN-卷积神经网络

    2020-08-05 16:39:13
    卷积运算 卷积运算可划分为三种:Same卷积...实现反卷积运算的核心步骤是在特征图中padding 0,然后进行卷积运算使得特征图变大。 FCN反卷积 首先对特征图各神经元之间进行0填充,即上池化;然后再进行卷积运算 ...
  • 改变网络结构, 图像重建由最后的反卷积上采样来实现; 采用自适应矩估计优化算法替换原本的随机梯度下降优化算法。分别在Set5和Set14测试集上进行对比实验, 实验结果表明, 改进算法在较少的训练时间下, 峰值信噪比...
  • tf.keras实现卷积神经网络 Keras 是一个用 Python 编写的高级神经网络 API,它能够以 TensorFlow, CNTK, 或者 Theano 作为后端运行。 Keras可以很明确的定义了层的概念,过来层与层之间的参数反倒是用户不需要...
  • 传统人脸检测算法往往不能自动地从原始图像中提取有用的检测特征,而卷积神经网络可以轻易地提取高维度的特征信息,广泛用于图像处理领域。针对上述缺点,采用简单高效的深度学习Caffe框架并通过AlexNet网络训练,...
  • 基于卷积神经网络的以图搜图算法实现 如果用这个名称去搜索论文,一定有不少。为什么了,因为从原理上来看,卷积神经网络就非常适合找图片的相似的地方。想想看,许多大牛、小牛、微牛的文章都是说如何从mnist中、...
  • 学习卷积神经网络的面部欺骗 “”论文的实现 结果 CASIA内测 原始数据集:或(密码:h5un) 规模 1.0 1.4 1.8 2.2 2.6 吝啬的 开发EER 0.1094 0.0408 0.0346 0.0339 0.0670 0.0571 测试HTER 0.1033 ...
  • Task7 卷积神经网络

    2019-03-14 23:23:23
    目录 1.定义 1.1 卷积运算的定义 1.2 动机(稀疏权重、参数共享、等变表示) 1.2.1 稀疏连接 ...2. 反卷积(tf.nn.conv2d_transpose) 2.1 卷积 2.2反卷积(后卷积,转置卷积) 2.3 代码实现 3...
  • 针对卷积神经网络图像超分辨率算法中的映射函数容易出现过拟合、梯度弥散等问题,提出一种由卷积网络和反卷积网络构成的复合卷积神经网络算法。提出使用RReLUs和Softplus函数结合形式作为激活函数,有效改善了过拟合...
  • 转置卷积(transposed convolution)是一种上采样技术,操作过程是卷积的反过程,也被称作反卷积(deconvolution),但它的操作结果不是卷积的逆。它也可以通过卷积操作来实现,只是需要将卷积核旋转180度。它主要...
  • 针对传统深度图超分辨率重建算法需要人工提取特征、计算复杂度较高且不容易得到合适表示特征的问题, 提出一种基于卷积神经网络(CNN)的深度图超分辨率重建算法。该算法不需要提前对特定的任务从图像中提取具体的手工...
  • 针对这一问题,提出基于双通道卷积神经网络的深度图超分辨率重建模型。该模型由深、浅两个通道组成,21层的深层通道通过联合卷积与反卷积,结合跳跃连接与多尺度理论,实现深度图细节特征的快速学习;3层的浅层通道...
  •  在深度学习的过程中,很多神经网络都会用到各种卷积核来进行操作,那么我们就简单讲一下卷积的原理和实现过程。 那么卷积神经网络中的作用是什么呢?一开始的传统神经网络是没有卷积层的,都是隐藏层加生全连接...
  • 为此,提出一种基于卷积神经网络(CNN)去噪正则化的条纹图高光区域修复算法。该方法仅需要在正常曝光和短曝光条件下获取两帧条纹图,快速实现条纹修复,步骤如下:利用Otsu方法对短曝光条纹的调制度图做二值化处理以确定...
  • 探讨卷积神经网络(Convonlutional Neural Network,CNN)在肝包虫病CT图像诊断中的应用。选取两种类型的肝包虫病CT图像进行归一化、改进的中值滤波去噪和数据增强等预处理。以LeNet-5模型为基础提出改进的CNN模型...
  • 一、 转载自卷积可视化 主要的四种可视化模式: 卷积核输出的可视化,即可视化卷积操作后的结果,...特征可视化,与第一种方法类似,但是输出的不再是卷积层的激活值,而是使用反卷积与反池化来可视化输入图像的...
  • 针对利用彩色图像进行车辆检测时会受到路面阴影、车辆反光和光线不足等复杂情况影响的问题,提出一种基于卷积神经网络并融合彩色与深度图像的车辆检测算法。设计单通道RG-D融合网络和双通道RGB-D融合网络两种改进模型...
  • 针对传统方法进行图像分割易受噪声影响问题,提出了一种基于全卷积神经网络的林木图像分割方法。该方法不需要对图像进行预处理,利用上池化和卷积层恢复图像分辨率,采用跳跃连接降低网络复杂度,同时避免了梯度...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 143
精华内容 57
关键字:

反卷积神经网络实现