如何用Bokeh可视化带权重的训练后Keras神经网络?
Keras神经网络交互式可视化(基于Bokeh)
Bokeh完全可以实现你需要的神经网络可视化需求,不管是权重分布、神经元活性展示都能通过它的交互式绘图能力完成。下面分步骤说明如何实现:
一、从Keras模型中提取关键数据
要可视化,首先需要从训练好的estimator中提取权重和神经元活性数据:
1. 提取层权重参数
每个Dense层的权重可以通过layer.get_weights()获取,返回的数组包含两部分:
- 第一部分是权重矩阵,形状为
(输入神经元数, 输出神经元数),对应层间神经元的连接权重 - 第二部分是偏置向量,形状为
(输出神经元数,),对应每个神经元的偏置值
示例代码:
# 获取第一个隐藏层的权重矩阵 first_layer_weights = estimator.layers[0].get_weights()[0] # 获取第一个隐藏层的偏置向量 first_layer_biases = estimator.layers[0].get_weights()[1]
2. 提取神经元活性值
要获取神经元的激活结果,需要构建一个辅助模型,输出原模型每个层的激活值:
from keras.models import Model # 构建输出各层激活值的模型 layer_outputs = [layer.output for layer in estimator.layers] activation_model = Model(inputs=estimator.input, outputs=layer_outputs) # 传入样本数据,得到各层激活结果(activations是列表,每个元素对应一层的激活值) # 这里取单个样本为例,也可以传入批量数据取平均 X_sample = X[0:1] activations = activation_model.predict(X_sample)
- 输入层的活性就是样本本身的特征值
- 隐藏层和输出层的活性对应
activations列表中对应位置的数组,形状为(样本数, 神经元数)
二、用Bokeh构建可视化网络
核心思路是将神经网络抽象为节点-边的网络图,通过节点属性(颜色、大小)展示活性,边的属性(颜色、粗细)展示权重:
1. 数据预处理:整理节点与边的信息
先定义各层的神经元数量,然后生成节点坐标、边的连接关系及对应权重:
import numpy as np # 定义各层神经元数量:输入层 + 所有Dense层 input_size = X.shape[1] layer_sizes = [input_size] + [layer.units for layer in estimator.layers] # 生成节点数据:每个神经元对应一个节点,按层水平排列 nodes = [] for layer_idx, size in enumerate(layer_sizes): for neuron_idx in range(size): node_data = { 'x': layer_idx, # 层索引作为x坐标,同一层x相同 'y': neuron_idx, # 神经元索引作为y坐标 'layer': f'Layer {layer_idx}', 'neuron_idx': neuron_idx } # 填充激活值 if layer_idx == 0: node_data['activation'] = X_sample[0][neuron_idx] else: node_data['activation'] = activations[layer_idx-1][0][neuron_idx] nodes.append(node_data) # 生成边数据:连接相邻层的神经元,携带权重信息 edges = [] for layer_idx in range(len(layer_sizes)-1): weights = estimator.layers[layer_idx].get_weights()[0] for in_neuron in range(layer_sizes[layer_idx]): for out_neuron in range(layer_sizes[layer_idx+1]): weight_val = weights[in_neuron, out_neuron] edges.append({ 'x0': layer_idx, 'y0': in_neuron, 'x1': layer_idx+1, 'y1': out_neuron, 'weight': weight_val, 'weight_abs': abs(weight_val) # 用于控制线条粗细 })
2. 绘制交互式网络图
用Bokeh的figure、segment(绘制边)、circle(绘制节点)构建可视化,并添加悬停工具查看细节:
from bokeh.plotting import figure, show from bokeh.models import ColumnDataSource, HoverTool, LinearColorMapper # 创建绘图对象 p = figure( title='Keras神经网络可视化', tools='pan,zoom_reset,box_zoom', x_axis_label='网络层', y_axis_label='神经元索引' ) # 绘制连接边:按权重正负区分颜色,粗细对应权重绝对值 # 正权重用红色,负权重用蓝色 positive_edges = [e for e in edges if e['weight'] > 0] negative_edges = [e for e in edges if e['weight'] <= 0] p.segment( x0='x0', y0='y0', x1='x1', y1='y1', source=ColumnDataSource(positive_edges), color='#ff4444', line_width='weight_abs', alpha=0.5 ) p.segment( x0='x0', y0='y0', x1='x1', y1='y1', source=ColumnDataSource(negative_edges), color='#33b5e5', line_width='weight_abs', alpha=0.5 ) # 绘制神经元节点:颜色映射对应激活值 color_mapper = LinearColorMapper(palette='Viridis256', low=0, high=1) node_source = ColumnDataSource(data=nodes) p.circle( x='x', y='y', source=node_source, size=12, fill_color={'field': 'activation', 'transform': color_mapper}, fill_alpha=0.8, line_color='black', line_width=1 ) # 添加悬停工具:显示节点和边的细节信息 node_hover = HoverTool(renderers=[p.renderers[2]]) node_hover.tooltips = [ ('层', '@layer'), ('神经元索引', '@neuron_idx'), ('激活值', '@activation{0.3f}') ] edge_hover = HoverTool(renderers=[p.renderers[0], p.renderers[1]]) edge_hover.tooltips = [ ('权重值', '@weight{0.3f}') ] p.add_tools(node_hover, edge_hover) # 显示绘图 show(p)
三、优化建议
- 如果输入层神经元数量较多,直接绘制所有边会导致画面杂乱,可以过滤掉权重绝对值小于阈值的边,减少视觉干扰。
- 针对批量样本的活性可视化,可以计算每个神经元的平均激活值,替换单个样本的激活值。
- Bokeh支持将可视化导出为HTML文件,方便后续交互查看。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

