NumPy(下):深度学习中的常用操作
一、文章背景与项目场景
本文以互联网教育推荐平台的图像分类项目为例,讲解深度学习项目中数据加载、训练与模型评估三个环节中频繁使用的 NumPy 操作。
无论使用 PyTorch、TensorFlow 还是 scikit-learn,读入数据时都会先转换成 NumPy 数组再进行后续操作。
二、数据加载阶段:图片读取
1. 图片读取工具
|
|
|
|
|---|---|---|
| Pillow |
|
np.asarray() 转换为 NumPy 数组
|
| OpenCV |
|
|
重要提醒:PyTorch 中很多图片操作基于 Pillow,遇到图片问题时应从 Pillow 角度出发思考。
2. 代码示例
Pillow 方式:
from PIL import Image
im = Image.open('jk.jpg')
im.size # 输出:(318, 116)
import numpy as np
im_pillow = np.asarray(im)
im_pillow.shape # 输出:(116, 318, 3)
OpenCV 方式:
import cv2
im_cv2 = cv2.imread('jk.jpg')
type(im_cv2) # 输出:numpy.ndarray
im_cv2.shape # 输出:(116, 318, 3)
3. 通道顺序的关键区别(重点)
|
|
|
|---|---|
|
|
|
|
|
|
★⚠️ 重要警告:模型训练时的通道顺序需与预测时的通道顺序保持一致。用 Pillow 训练、用 OpenCV 读图预测,不会报错但结果不正确!
三、数组的索引与切片
NumPy 数组的索引与 Python 列表相同,同样支持切片索引。
重点语法:冒号 : 代表全部选中。
im_pillow[:, :, 0] # 取图片第0个通道(R通道)的所有数据
提取三个通道:
im_pillow_c1 = im_pillow[:, :, 0] # R通道
im_pillow_c2 = im_pillow[:, :, 1] # G通道
im_pillow_c3 = im_pillow[:, :, 2] # B通道
四、数组拼接:np.concatenate()
语法:np.concatenate((a1, a2, ...), axis=0)
-
a1, a2, …:要合并的数组 -
axis:沿哪一个维度合并,默认沿 0 轴
常见报错——维度不一致导致 axis 越界:
# 错误示例:im_pillow_c1是2维(116,318),zeros是3维(116,318,1)
np.concatenate((im_pillow_c1, zeros, zeros), axis=2)
# 报错:AxisError: axis 2 is out of bounds for array of dimension 2
五、增加数组维度的方法
方法一:使用 np.newaxis
im_pillow_c1 = im_pillow_c1[:, :, np.newaxis]
im_pillow_c1.shape # 输出:(116, 318, 1)
★该操作在深度学习代码中很常见,PyTorch 中对应
unsqueeze(),TensorFlow 中使用tf.newaxis。
方法二:直接赋值
im_pillow_c2_3ch = np.zeros(im_pillow.shape)
im_pillow_c2_3ch[:,:,1] = im_pillow_c2
六、深拷贝(副本)与浅拷贝(视图)——重点概念
概念对比
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
创建方式
|
|
|
|---|---|
np.array() |
|
np.asarray() |
|
view() |
|
copy() |
|
| 切片操作 |
|
浅拷贝示例
a = np.arange(6) # [0 1 2 3 4 5]
b = a.view()
b.shape = 2, 3
b[0,0] = 111
print(a) # [111 1 2 3 4 5] ← 原数组也被修改!
只读数组问题(重要坑点)
im_pillow = np.asarray(im) # 浅拷贝,Pillow数据只读
im_pillow[:,:,1:] = 0# 报错:ValueError: assignment destination is read-only
解决方法:改用深拷贝 np.array():
im_pillow = np.array(im) # 深拷贝,可修改
im_pillow[:,:,1:] = 0# 成功
七、模型评估阶段的重要函数
1. np.argmax() —— 求最大值对应的索引
np.argmax(probs) # 返回概率最大值对应的类别索引
2. np.argmin() —— 求最小值对应的索引
用法与 argmax 相同。
3. np.argsort() —— 排序后返回原数组索引
语法:np.argsort(a, axis=-1, kind=None)
-
对原数组从小到大排序,返回对应元素在原数组中的索引
示例——找出概率最大的前3个类别:
probs = np.array([0.075, 0.15, 0.075, 0.15, 0.0, 0.05, 0.05, 0.2, 0.25])
probs_idx_sort = np.argsort(-probs) # 加负号,降序排序
probs_idx_sort[:3] # array([8, 7, 1]) ← 概率最大的3个类别索引
八、函数汇总表
|
|
|
|
|---|---|---|
view() |
|
|
copy() |
|
|
concatenate() |
|
|
argmax() |
|
|
argsort() |
|
|
九、每课一练
题目:给定数组 scores,形状为 (256, 256, 2),scores[:, :, 0] 与 scores[:, :, 1] 对应位置元素和为 1。要求:scores 通道 0 的值大于通道 1 的值时,mask 对应位置为 0,否则为 1。
参考解答:
# 解答一:利用 argmax
mask = np.argmax(scores, axis=2)
# 解答二:条件判断
mask = (scores[:, :, 0] < scores[:, :, 1]).astype('int')
十、小结
-
数据加载阶段:掌握 Pillow 与 OpenCV 读取图片的区别,注意通道顺序一致。 -
数据处理阶段:熟练使用索引、切片、拼接( concatenate)和维度扩充(np.newaxis)。 -
深拷贝与浅拷贝:理解 view()和copy()的区别,避免因浅拷贝导致的隐形 bug。 -
模型评估阶段:掌握 argmax、argmin、argsort的用法,高效处理模型输出结果。 -
核心建议:理解"轴"(axis)的概念是掌握本节内容的关键,多动手练习才能融会贯通。

