1 提问的艺术
数学界有个说法,提出问题的艺术比解决问题的艺术更加重要.
一个极简的线性回归代码大概是这个样子:
data = pd.read_csv('./dataset/Income1.csv')
plt.scatter(data.Education, data.Income)
x = data.Education
y = data.Income
# 顺序模型
model = tf.keras.Sequential()
# 添加Dense层 建立模型 输出维度1 输入维度1
model.add(tf.keras.layers.Dense(1, input_shape=(1,)))
# 输出模型信息
model.summary()
# 模型编译 优化算法:adam 损失函数:mse
model.compile(optimizer='adam', loss="mse")
# 训练 训练次数5000
history = model.fit(x, y, epochs=5000)
# 预测
y_predict = model.predict(x)
print(y_predict)
在学习了Tensorflow单变量线性回归之后,对于一个纯小白,我们可以提出怎样的问题呢?
对以上代码进行分析,可知大致分为 加载数据->训练->预测 3个步骤.
当然可以找到一些实际的项目案例,照搬其中的架构模式.并且可以从多个项目中择优重组,实现所谓的创新.
但是,经验的学习是个无边界的问题,且经验的模仿也是个机械性的问题.模仿的短期利益带来的后果是长期的能动力丧失.而且我坚信,即使是零碎的稚嫩的思考也胜于企业级的模仿,原因是后者无论是对于个人还是对于世界都没有实质性的推动.
数据的收集与存储
当数据量到达一定规模,计算(训练\预测)与存储分离是必须的.
以抖音推荐为例,海量用户的数据量是相当庞大的,这里需要采用HDFS这类大数据存储引擎吗?
我想答案应该是否定的,原因是虽然数据总量大,但是训练时要有目标的提取用户数据(比如提取单个用户数据或者一组用户数据),如果使用聚合而成的大数据文件存储,则在训练之前无形增加了一步MR操作.故类似GlusterFS\Ceph这类存储方案似乎是更好的选择,即问题不是单个文件的大小而是大量并不太大的文件的存储与获取问题.
另外就是训练的并行问题,需要对每个用户进行模型训练吗?如果是的话,将对训练节点产生非常大的压力(亿级训练线程),我能想到的一种方式是将用户分组,然后将一组用户进行数据拼接然后增加一个用户标识的维度.
进一步可以想到的是,不仅可以匹配用户对于内容的相关性,同时还可以找到用户与用户间的相关性.也就是说,训练的x是用户的抽象特征维度(年龄\性别\学历\兴趣等),而不是对于具体的人进行匹配.这样可以大大的减少计算量,但会降低推荐精度,实际上做的是群体性推荐.
另外一个需要考虑的问题是数据的全量与增量问题.
如果对于增量到达一定阈值时或者定时的,进行全量数据的训练(全历史数据),训练计算的规模将越来越大.这种情况下,是不是会对部分历史数据(比如去年的数据)进行舍弃?这里暂时没有思路.
对于数据的增量收集问题,后续将使用websocket+minio的方式进行模拟.
触发方式
首先,数据训练是个比较耗时的过程.对于此类过程,就不期望能够用户交互式的触发.能够想到以下几种触发方式:
- 自动触发 当持续收集的数据量到达一个阈值触发训练程序,定时的任务调度,或者上游程序(比如ETL)完成后触发
- 手动触发 为运维人员提供交互式界面手动触发,由于训练节点是单机的,这里并不必须的做成Web UI.但从技术栈考虑,Web页面丰富的展现形式仍然是优势(见2.1).且对于大规模的训练任务,期望能做成分布式训练并实时跟踪各节点的训练情况.从资源消耗的角度,一个非高并发的Web服务器并不消耗过多的资源.
物联网
特别的,这里考虑一下物联网边缘设备.
矛盾在于边缘设备的资源限制与云计算的可靠性问题(既包括网络可靠性也有网络安全的考虑).期望能发挥云计算的算力同时保证可靠性.当边缘设备持续不断的收集终端数据之后,分批次的(或者实时的-socket)上传到云服务器,由云服务器进行数据训练(清洗),然后将训练后的模型下载到边缘设备.这样通过限定特定端口与云服务器的权限保证安全性.即使对于断网的情况,边缘设备仍然可以使用旧版的模型执行预测.并且,边缘设备也可以暂时承担起训练的任务.
对于非核心终端(比如传感器)的控制权,直接上云也未尝不可.但数据的加密仍是个需要考虑的问题.
预测
预测是实时的过程.而且预测的即时性是个关键性的指标(滞后的还能叫预测?考虑一下股票预测)
考虑一下两个预测场景:
- 交互式预测 即用户操作触发预测,比如发情期的哺乳动物配对游戏
这里考虑服务器并发问题,将训练节点与预测节点(集群)分离,训练节点侧重GPU性能,预测节点侧重CPU并发性能.
- 实时预测 各种流式数据,无论是flv\websocket\mqtt\flink\kafka等.
这里考虑网络IO与延迟.使用压缩算法提取关键特征矩阵,并可以通过矩阵拼接(即包括不同媒体数据的多维度拼接也包括多个相同设备数据的同维度拼接)降低传输成本
这里重点考虑智能设备(如自动驾驶\无人(战斗)机).
一方面,自主决策设备本身载有预测模型,同时数据在源源不断的产生.可以考虑由云服务器进行训练后,更新模型.同时云端对于设备进行必要的干预.对于战略性决策(比如向敌机开火),将指挥权移交云端(基站).
另一方面,关于两个智能设备的对抗问题,比如两个无人驾驶汽车迎面驶来,做出向同侧转弯的预测.这里引出两个问题,对抗模型与局外人模型.
对抗模型
考虑以下几种场景: 下棋\公司竞争\狮子捕杀羚羊\无人机交战\职(官)场斗争 -> 博弈论
关键问题不是超参数的选择,而是以何种模型应对对方的模型.
对于二人的典型场景,对方可能采取一报还一报\二报还一报\大公无私\拒不合作等等起手方式,当时当我方做出决策后,对方的模型可能因此也发生变化.基于对方的实时数据,对对方现有模型进行预测,并采取对应的模型进行对抗.基于对方模型(意识形态\人格特质)的滞后性,方可使我方利于不败之地.
这里有个问题是脏数据问题(障眼法),通过做出迷惑性行为是对方采取错误的模型达到我方预期目标.
对于这种模型选择问题,我将其命名为超模型.超模型问题与局外人是相关联的,无论是从派出所民警的角度还是公司高层的角度肯定不希望局势失控而采取特定的策略进行干预.
对于多个模型对抗过程的通信(消息传递)\局部联合对抗\外部干预,这是个很有意思的问题.特别是单模型如何破局的问题,这就是命运.对于个体而言,需要的肯定不仅仅是对抗均衡,而是在放弃部分自身利益的情况下进行强联合甚至于实现做局者的过程,局中局外都是宿命,但对抗不是.
2 实现
2.1 flask训练预测交互
后端flask代码
这里使用全局model对象是合适的,model并不是session相关的(即不绑定用户线程)
model = None
training_flag = 0
# 训练模型(手动触发)
@app.route('/train', methods=['POST'])
def train():
global model, training_flag
training_flag = 0
data = pd.read_csv('./dataset/Income.csv')
x = data.Education
y = data.Income
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, input_shape=(1,)))
model.compile(optimizer='adam', loss="mse")
model.fit(x, y, epochs=500)
training_flag = 1
return 'success'
# 训练结束标识
@app.route('/training_flag', methods=['GET'])
def training_flag():
global training_flag
return {
'training_flag': training_flag
}
# 预测
@app.route("/predict", methods=['POST'])
def predict():
json_data = request.get_json()
x_predict = json_data['x_predict']
global model
y_predict = model.predict(tuple(x_predict))
return {
'y_predict': np.array(y_predict).tolist()
}
# 上传
@app.route('/upload', methods=['POST'])
def upload():
f = request.files['file']
f.save('./dataset/Income.csv')
return 'success'
前端代码略
效果图
a 更新日志
2020-10-20 21:00 更新flask web交互式实现
2020-10-20 22:00 更新关于数据存储和收集的思考
b 待办列表
- websocket + minio模拟实时数据收集