tensorflow经验总结(持续更新)
经验教训:
在训练神经网络时, 建议每次加载一批随机的图像进行 previewing(观察)。当遇到神经网络的 loss 值较大或者出现异常结果时, 应采取措施排查问题, 具体包括: 一是检查网络架构是否存在问题; 二是确认预处理步骤是否正确无误.
def sample_stack(stack, rows=6, cols=6, start_with=0, show_every=5):
"""
批量展示图片,很好用的工具
args:
stack: shape:(N,H,W), value range:[0-1]
show_every:可以调整步长
"""
fig,ax = plt.subplots(rows,cols,figsize=[18,18])
for i in range(rows*cols):
ind = start_with + i*show_every
ax[int(i/cols),int(i % cols)].set_title('slice %d' % ind)
ax[int(i/cols),int(i % cols)].imshow(stack[ind],cmap='gray')
ax[int(i/cols),int(i % cols)].axis('off')
plt.show()
代码解读
2、在使用tensorflow-gpu时首次报错后重新运行会遇到内存不足的问题,在查阅显卡剩余空间后发现其并未留有充足余地空间;然而当前正在运行的线程显示为空状态,则不得不退出登录并重新进入虚拟环境;幸运的是问题迎刃而解,并且此时显卡又恢复了足够的存储空间可用;目前尚无法确定具体原因是什么。
知识杂记
第一次:
1、ResNet在经历降采样过程时会将通道数量翻倍以避免因降采样导致的信息损失。
2、VGGNet带来的启发包括:
2.1 网络深度越深;
2.2 建议更多采用大小为3×3的卷积核;
2.3 两个连续的3×3卷积相当于一层5×5的卷积核(相同感受野且参数量更少);
2.4 采用1×1卷积核可以实现非线性变换功能;
2.5 每经历一次池化操作都会使通道数量翻倍。
3、关于Dropout原理的理解可以从以下三个角度展开解释:
3.1 每次执行Dropout操作相当于训练了一个子网络模型;
3.2 其背后的动机是为了减少神经元之间的依赖关系从而提高泛化能力;
3.3 从数据层面来看相当于进行了某种数据增强操作。
4、动量梯度下降方法不仅体现在参数更新幅度上更体现在优化方向上:
4.1 在初始阶段利用动量积累来加速优化过程;
4.2 在接近局部极值区域时梯度趋于零状态但由于动量作用能够跳出局部最优陷阱;
4.3 当优化方向发生变化时动量能够帮助缓解振荡现象。
5、对于卷积层参数数量计算问题:由于采用了参数共享机制所以每一层的参数数量计算应基于其输入特征图尺寸及滤波器大小等多方面因素综合考虑。
6、全连接层之后不再使用后续的卷积层是因为全连接层已经消除了图像样本的空间位置信息;
7、在图像与标签进行拼接操作时建议沿横向和纵向分别进行拼接操作(即使用np.hstack(data)和np.vstack(data)函数)。
a=[1,1,1] # 模拟单张图片数据,若a是array,结果一样
b=[2,2,2] # 模拟单张图片数据
data=[] # 模拟训练集
data.append(a) # 模拟循环时数据的读取过程
data.append(b)
data1=np.vstack(data) # 模拟拼接
data1
Out[38]:
array([[1, 1, 1],
[2, 2, 2]])
data1.shape
Out[39]: (2, 3)
data2=np.hstack(data) # 一定要注意,对于图片对应的标签来说得这样!!
data2
Out[41]: array([1, 1, 1, 2, 2, 2])
data2.shape
Out[42]: (6,)
代码解读
8、如何打乱训练集顺序
# 以上面的data1为例
data1[[1,0]] # 这种操作不会改变data1原先的结构
Out[43]:
array([[2, 2, 2],
[1, 1, 1]])
"""
其实这种更常见,因为我们需要的经常是 x, ground_truth一起进行乱序
"""
p = np.random.permutation(2)
p
Out[47]: array([0, 1])
data_new = data1[p]
"""
注意 np.random.shuffle会直接改变原数组顺序
"""
data_new
Out[49]:
array([[1, 1, 1],
[2, 2, 2]])
代码解读
第二次更新:
1、对于tensorflow,即使机器有多个cpu,tf也不会区分它们,所有的cpu都使用/cpu:0作为名称,而一台机器上不同gpu的名称是不同的,例如第一个叫/gpu:0,第二个叫/gpu:1,等等。
默认情况下,tf只会将运算优先放到gpu:0上。
2、经常见到sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=False))
allow_soft_placement=True表示如果运算无法由gpu执行,那么tf会自动将它放到cpu上执行
注意,tensorflow的kernel定义了哪些操作可以跑在gpu上。
log_device_placement=True表示输出运行每一个运算的设备
3、并行化深度学习模型的训练方式有两种,Data parallelism, Model parallelism
(1)Model parallelism: Different GPUs run different part of the code. Batches of data pass through all GPUs.
(2)Data parallelism: Use multiple GPUs to run the same code. Each GPU is feed with different batch of data.
Data parallelism每一轮迭代都需要统一开始,统一结束,因此当每个GPU的memory和computation capacity相近时,最好采用Data parallelism.
4、有两种方式可以将Numpy array从main memory 拷贝进GPU memory:
(1)给session用feed_dict传递array
(2)tf.constant加载array为tensor
5、tensor.get_shape()获取的是静态的shape,是在图构建时由python wrappers计算的,静态的不会包含batch_size,tf.shape(tensor)是运行时计算的,可以获得包括batch_size的shape。
6、transpose convolution输出size的计算公式:
same padding: trans_conv_size = input_size * stride
valid padding: trans_conv_size = input_size * stride + max( filter_size - stride, 0 )
7、对于tensor t,t.eval() == tf.get_default_sesion().run(t)
8、注意下面这段代码:
w = tf.constant(3)
x = w + 2
y = x + 5
with tf.Session() as sess:
print(y.eval())
print(z.eval())
代码解读
上面的这段中,在计算y的过程中会依次求出w和x;而在求取z的过程中也会重新进行一次w和x的运算!这是因为图运行之间会清除所有节点值(除了通过session维持的变量值),因此为了提高效率只需让TensorFlow在同一轮图运行中同时评估y和z即可,请看以下代码:
with tf.Session() as sess:
y_val, z_val = sess.run([y,z])
print(y_val)
print(z_val)
代码解读
实际上,在深度学习模型中使用激活层如ReLU时会遇到一个问题:该层会对输入中的所有负数值进行抑制(即置零),而如果在应用ReLU之前先对数据进行归一化处理,则原本非负的数据也会被转换为负值。这会导致这些正值在经过ReLU作用后被置零。这与我们应用Batch Normalization的目的背道而驰
对于使用matplotlib.py库时来说,在一个图像窗口中同时显示三行三列共九张图片是没问题的做法
import matplotlib.pyplot as plt
rows = cols = 3
name = 'images.png'
# figsize:width,height
fig,ax = plt.subplots(3,3,figsize=[18,18])
for i in range(rows*cols):
ax[int(i/cols),int(i % cols)].set_title('slice %d' % i)
# image shape:(N,height,width)
ax[int(i/cols),int(i % cols)].imshow(image[i],cmap='gray')
ax[int(i/cols),int(i % cols)].axis('off')
# 这句话要在show之前调用,否则show函数展示完之后会创建新的空白图,保存的话,也就是空白图了
plt.savefig(name)
plt.show()
代码解读
然而,在某个行或列仅剩一个元素时,
ax[int(i/cols),int(i % cols)]
这样的做法会引发错误,
IndexError: too many indices for array
必须将其表示为ax[int(i%cols)]的形式。
