zoukankan      html  css  js  c++  java
  • TensorFlow使用记录 (二): 理解tf.nn.conv2d方法

    方法定义

    tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format="NHWC", dilations=[1,1,1,1], name=None)

    参数:

    • input 输入的要做卷积的数据体,要求是一个`Tensor`
    • filter: 卷积核,要求也是一个`Tensor`, shape= [filter_height, filter_width, in_channels, out_channels], 其中 filter_height 为卷积核高度,filter_weight 为卷积核宽度,in_channel 是要做卷积的数据体的通道数 ,out_channel 是卷积核数量。
    • strides: 卷积步长(1-D tensor of length 4), shape=[1, strides, strides, 1],第一位和最后一位固定是1
    • padding: A `string` from: `"SAME", "VALID"`. "SAME" 表示使用0去填充边界, "VALID"则不填充
    • data_format: An optional `string` from: `"NHWC", "NCHW"`. Defaults to `"NHWC"`.
      Specify the data format of the input and output data.
      With the default format "NHWC", the data is stored in the order of:  [batch, height, width, channels].

    • name: A name for the operation (optional).

    具体实现

    input shape: [batch, in_height, in_width, in_channels]

    filter shape: [filter_height, filter_width, in_channels, out_channels]

    计算过程:

    1. 将filter展开成2-D matrix, shape: [filter_height*filter_width*in_channels, output_channels]

    2. 从input tensor中提取patches构成一个virtual tensor, shape: [batch, out_height, out_width, filter_height*filter_width*in_channels]

    3. 对于每一个patch,右乘上1中的filter matrix。即 [batch, out_height, out_width, filter_height*filter_width*in_channels] x [filter_height * filter_width * in_channels, output_channels], 那么输出的shape: [batch, out_height, out_width, output_channels]

    【注:必须有 strides[0] = strides[3] = 1】。绝大多数情况下,水平的stride和竖直的stride一样,即strides = [1, stride, stride, 1]。

    输出结果的shape计算:

    在caffe中是这样的:

    out_height =floor(in_height+2*pad-filter_height)/stride+1; floor向下取整

    out_width=floor(in_width+2*pad-filter_width)/stride+1

    在TensorFlow中是这样的:

    "SAME" 类型的padding:

    out_height = ceil(in_height / strides[1]); ceil向上取整

    out_width = ceil(in_width / strides[2])

    "VALID"类型的padding:

    out_height = ceil((in_height - filter_height + 1) / striders[1])

    out_width = ceil((in_width - filter_width + 1) / striders[2]

     验证代码

    # -*- coding:utf-8 -*-
    
    from __future__ import division
    import tensorflow as tf
    import numpy as np
    import math
    import pandas as pd
    
    input_arr = np.zeros((12, 15), dtype=np.float32)
    number = 0
    for row_idx in range(input_arr.shape[0]):
        for col_idx in range(input_arr.shape[1]):
            input_arr[row_idx][col_idx] = number
            number +=1
    
    number = 6
    w_arr = np.zeros((2, 3), dtype=np.float32)
    for row_idx in range(w_arr.shape[0]):
        for col_idx in range(w_arr.shape[1]):
            w_arr[row_idx][col_idx] = number
            number += 1
    
    stride = [1, 1, 1, 1]
    
    # 从卷积的定义【实际上不是卷积,而是cross-correlation】进行计算验证---对VALID类型卷积进行
    res_shape_h = int(math.ceil((input_arr.shape[0] - w_arr.shape[0] + 1) / stride[1]))
    res_shape_w = int(math.ceil(input_arr.shape[1] - w_arr.shape[1] + 1) / stride[2])
    validation_res = np.zeros(shape=(res_shape_h, res_shape_w), dtype=np.float32)
    
    for row_idx in range(validation_res.shape[0]):
        for col_idx in range(validation_res.shape[1]):
            patch = input_arr[row_idx : row_idx+w_arr.shape[0], col_idx : col_idx+w_arr.shape[1]]
            # 这里的 * 实际上代表的是点积,即对应元素位置相乘
            res = np.sum(patch * w_arr)
            validation_res[row_idx][col_idx] = res
    
    print('result of convolution from its definition: validation_res')
    print(validation_res)
    pd.DataFrame(validation_res).to_csv('validation_res.csv', index = False, header=False)
    
    # 从TensorFlow实现出发
    input_arr = np.reshape(input_arr, [1, input_arr.shape[0], input_arr.shape[1], 1])
    w_arr = np.reshape(w_arr, [w_arr.shape[0], w_arr.shape[1], 1, 1])
    
    # 输入Tensor, shape: [1, 12, 15, 1]
    net_in = tf.constant(value=input_arr, dtype=tf.float32)
    
    # filter, shape: [2, 3, 1, 1]
    W = tf.constant(value=w_arr, dtype=tf.float32)
    
    # TensorFlow卷积的计算结果
    # valid卷积结果, shape: [1, 11, 13, 1]
    result_conv_valid = tf.nn.conv2d(net_in, W, stride, 'VALID')
    # same卷积结果, shape: [1, 12, 15, 1]
    result_conv_smae = tf.nn.conv2d(net_in, W, stride, 'SAME')
    
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        valid_conv_res, same_conv_res = sess.run([result_conv_valid, result_conv_smae])
    
    print(valid_conv_res.shape)
    valid_conv_res = np.reshape(valid_conv_res, [valid_conv_res.shape[1], valid_conv_res.shape[2]])
    same_conv_res = np.reshape(same_conv_res, [same_conv_res.shape[1], same_conv_res.shape[2]])
    print('TensorFlow con res: valid_conv_res')
    print(valid_conv_res)
    pd.DataFrame(valid_conv_res).to_csv('conv_res.csv', index=False, header=False)
    pd.DataFrame(same_conv_res).to_csv('same_res.csv', index=False, header=False)
  • 相关阅读:
    2020年12月学习记录
    Data Protection Application Programming Interface滥用攻击
    另类的缓存凭证收集
    js获取地址栏参数,携带参数跳转页面
    用JS获取地址栏参数的方法
    解决vue加载时闪烁
    vue-cli-service build 不同环境配置
    vite创建vue3.x项目报404的解决方案
    后端开发完接口才给出接口文档,合理吗?
    API研发实现规范化管理的价值
  • 原文地址:https://www.cnblogs.com/xuanyuyt/p/9690669.html
Copyright © 2011-2022 走看看