numpy和tensorflow中的关于参数axis的正确理解

首先声明:axis的默认值不是0,这一点我发现很多博客文章都搞错了。所以一定要知道,axis的默认值不是0

当给axis赋值为0时,和采取默认值时的表现是完全不同的,从下面的代码就可以看出。

>>> z #大小为2×3×4的数组
array([[[ 2,  3,  4,  8],
        [ 3,  1,  4,  1],
        [ 6,  3,  2,  6]],

       [[10,  2, 45,  2],
        [ 2,  4,  5, 10],
        [22,  4,  4,  1]]])
>>> np.sum(z,axis=0)  # axis=0
array([[12,  5, 49, 10],
       [ 5,  5,  9, 11],
       [28,  7,  6,  7]])
>>> np.sum(z)   #axis不指定,取默认值
154

刚开始学习numpy和tensorflow的朋友经常遇到类似下面这样的一些函数:

#python
x=[[1,2],[5,1]]
x=np.array(x)
z1=np.max(x,axis=0)
z2=np.max(x,axis=1)


#tensorflow
x=tf.constant([[1.,2.],[5.,2.]])  
x=tf.shape(x)  
z1=tf.reduce_max(x,axis=0)#沿axis=0操作  
z2=tf.reduce_max(x,axis=1)#沿axis=1操作

类似的还有argmax,sum等等函数,它们都含有一个名为axis的参数,那这个参数到底是什么意思呢?一句话总结就是:沿着axis指定的轴进行相应的函数操作

直接看这句话可能看不懂,下面用一个最简单的例子来说明一下。

import numpy as np
#首先,创建一个2×3维的numpy的array数组
x=[[2,3,4],[1,2,5]]
x=np.array(x)
#然后,计算不同参数下np.max的输出

print(np.max(x))
# 5
print(np.max(x,0))
# [2,3,5]
print(np.max(x,1))
# [4,5]

可以看到,如果不知道axis,那么默认就是取得整个数组的最大值,这相当于把多维数组展开成一维,然后找到这个一维数组里的最大值。
而当axis=0时,直观上来看就是取得每一列的最大值,源数组总共为2行3列,所以最终的输出包含3个元素。
当axis=1时,就相当与是取每一行的最大值。

上面的理解方式在二维数组还比较直观,但是如果数组达到3维4维甚至更高维时,就不能简单的从行列角度出发去理解了,这时应该考虑从“轴”的角度来看。首先,明确一点,“轴”是从外向里的,也就是说,最外层的是0轴,往内一次是1轴,2轴… 。 具体可以看下面的例子:

>>> z
array([[[ 2,  3,  4,  8],
        [ 3,  1,  4,  1],
        [ 6,  3,  2,  6]],

       [[10,  2, 45,  2],
        [ 2,  4,  5, 10],
        [22,  4,  4,  1]]])
>>> z.shape
(2, 3, 4)

可以看到,这是一个2×3×4的三位数组,其中0轴对应第一维(2),1轴对应第二维(3),2轴对应第三维(4)。当我们指定了函数按某一轴来计算时,函数的输出数组的shape就是去掉当前轴的shape,如下所示。

>>> np.max(z,axis=0).shape
(3, 4)
>>> np.max(z,axis=1).shape
(2, 4)
>>> np.max(z,axis=2).shape
(2, 3)

而对于输出数组的每一个元素output[i][j]的值,实际上就是z[i][...][j]集合中的最大值,如下面的代码所示。其中当axis=0时,输出数组output的shape为3×4,其中output.[2][3]的值,实际上就是z[0][2][3],z[1][2][3]的最大值,也就是(6,1)中的最大值,即为output.[2][3]=6

再如axis=1时,输出数组output的shape为2×4,其中output.[1][2]的值,实际上就是z[1][0][2],z[1][1][2],z[1][2][2]中的最大值,也就是(45,5,4)中的最大值,即为output.[1][2]=45]

>>> np.max(z,axis=0)
array([[10,  3, 45,  8],
       [ 3,  4,  5, 10],
       [22,  4,  4,  6]])
>>> np.max(z,axis=1)
array([[ 6,  3,  4,  8],
       [22,  4, 45, 10]])
>>> np.max(z,axis=2)
array([[ 8,  4,  6],
       [45, 10, 22]])

用形式化的数学语言总结上面的过程就是:
对于大小为[i,j,k]的输入数组z,假设axis=0,那么输出矩阵output的大小就为[j,k],并且output的每一个元素的计算方式如下:

output[j,k]=maxi(z[i,j,k]) o u t p u t [ j , k ] = max i ( z [ i , j , k ] )

如果axis=1,那么输出矩阵output的大小就为[i,k],并且output的每一个元素的计算方式如下:

output[i,k]=maxj(z[i,j,k]) o u t p u t [ i , k ] = max j ( z [ i , j , k ] )

对于4维,5维甚至无限维的情况,计算方法是一样的,你不妨自己推导一下,如果有任何问题,欢迎可以在评论中留言。

另外,对于其他的sum,argmax等等函数中的计算方法也是一样的,只需要把函数max换成对应的函数即可,如下所示:

sum:

output[j,k]=i(z[i,j,k]) o u t p u t [ j , k ] = ∑ i ( z [ i , j , k ] )

argmax:
output[j,k]=argmaxi(z[i,j,k]) o u t p u t [ j , k ] = a r g m a x i ( z [ i , j , k ] )

``` import numpy as np import tensorflow as tf from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout import matplotlib.pyplot as plt import cv2 tf.random.set_seed(42) # 定义路径 train_dir = r'C:\Users\29930\Desktop\结构参数图' validation_dir = r'C:\Users\29930\Desktop\测试集路径' # 需要实际路径 # 图像参数 img_width, img_height = 150, 150 batch_size = 32 # 数据生成器 train_datagen = ImageDataGenerator( rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) test_datagen = ImageDataGenerator(rescale=1./255) train_generator = train_datagen.flow_from_directory( train_dir, # 修改为实际路径 target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary') validation_generator = test_datagen.flow_from_directory( validation_dir, # 修改为实际路径 target_size=(img_width, img_height), batch_size=batch_size, class_mode='binary') # 模型构建 model = Sequential([ Conv2D(32, (3,3), activation='relu', input_shape=(img_width, img_height, 3)), MaxPooling2D(2,2), Conv2D(64, (3,3), activation='relu'), MaxPooling2D(2,2), Flatten(), Dense(128, activation='relu'), Dropout(0.5), Dense(1, activation='sigmoid') ]) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) # 训练模型 history = model.fit( train_generator, steps_per_epoch=len(train_generator), epochs=20, validation_data=validation_generator, validation_steps=len(validation_generator)) # Grad-CAM函数修正版 def generate_grad_cam(model, img_array, layer_name): # 创建梯度模型 grad_model = tf.keras.models.Model( inputs=[model.inputs], outputs=[model.get_layer(layer_name).output, model.output] ) # 计算梯度 with tf.GradientTape() as tape: conv_outputs, predictions = grad_model(img_array) loss = predictions[:, 0] # 获取梯度 grads = tape.gradient(loss, conv_outputs) pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2)) # 生成热力图 conv_outputs = conv_outputs[0] heatmap = tf.reduce_sum(conv_outputs * pooled_grads, axis=-1) # 归一化处理 heatmap = np.maximum(heatmap, 0) heatmap /= np.max(heatmap) return heatmap # 可视化部分 X, y = next(validation_generator) sample_image = X[0] img_array = np.expand_dims(sample_image, axis=0) # 获取最后一个卷积层(根据模型结构调整索引) last_conv_layer = model.layers[2] # 第二个Conv2D层 heatmap = generate_grad_cam(model, img_array, last_conv_layer.name) # 调整热力图尺寸 heatmap = cv2.resize(heatmap, (img_width, img_height)) heatmap = np.uint8(255 * heatmap) # 颜色映射 jet = plt.colormaps.get_cmap('jet') jet_colors = jet(np.arange(256))[:, :3] jet_heatmap = jet_colors[heatmap] # 叠加显示 superimposed_img = jet_heatmap * 0.4 + sample_image superimposed_img = np.clip(superimposed_img, 0, 1) # 绘制结果 plt.figure(figsize=(12, 4)) plt.subplot(131) plt.imshow(sample_image) plt.title('原始图像') plt.axis('off') plt.subplot(132) plt.imshow(heatmap, cmap='jet') plt.title('热力图') plt.axis('off') plt.subplot(133) plt.imshow(superimposed_img) plt.title('叠加效果') plt.axis('off') plt.tight_layout() plt.show()```完善代码使在构建模型后,调用模型初始化各层形状,随后指定输入形状并通过实际数据前向传播来触发形状推断.输出完整代码
最新发布
03-24
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值