|
AI开发与传统开发
传统开发:需求分析,设计开发,测试 --- bug ,修订bug -- 上线
AI开发
- 先设定一个baseline,
- 大概率这个baseline存在很多可优化的地方,但这不叫bug
- 做一些优化,数据方向的,模型方向的,可以让模型的效果更好
- AI开发的对与错没有传统开发类似bug这样清晰的错误的界定
- 而是一个由效果由坏到好的过程,直到很难再提升为止
训练器示例 from sklearn.svm import SVC,SVR model = SVR()
from tpf import MlTrain
MlTrain.train(X_train, y_train, X_test, y_test,
model,
save_path="fangjia_SVR.pkl",
epoch=300000,
loss_break=0.1)
模型加载验证
from tpf import pkl_load,pkl_save
model,loss=pkl_load(file_path=save_path)
y_pred_dtr = model.predict(X_test)
((y_pred_dtr - y_test)**2).mean()
|
from tpf.datasets import load_boston X_train, y_train, X_test, y_test = load_boston(split=True,test_size=0.15, reload=False) X_train.shape,y_train.shape, X_test.shape, y_test.shape from sklearn.tree import DecisionTreeRegressor dtr = DecisionTreeRegressor() dtr.fit(X_train,y_train) feature=dtr.feature_importances_ import numpy as np a=np.argsort(feature)[::-1] X_train = X_train[a][:6] y_train = y_train[a][:6] X_test = X_test[a][:6] y_test = y_test[a][:6] save_path="fangjia_DecisionTreeRegressor.pkl" from sklearn.tree import DecisionTreeRegressor model = DecisionTreeRegressor()
from tpf import MlTrain
MlTrain.train(X_train, y_train, X_test, y_test,
model,save_path=save_path,epoch=1000)
loss_start: 2.994999999999996
from tpf import pkl_load,pkl_save model,loss=pkl_load(file_path=save_path) y_pred_dtr = model.predict(X_test) ((y_pred_dtr - y_test)**2).mean() |
|
数据集:100个特征列,2类标签 from yinum import get_train,get_test from yinum import DLModel from yinum import T import torch
model = DLModel(in_features=100, out_features=2)
参数以ml_开头,方便查看
T.train(model,
loss_fn=torch.nn.CrossEntropyLoss(),
optimizer='sgd',
train_dataset_func=get_train,
test_dataset_func=get_test,
train_dataset=None,
test_dataset=None,
train_dataloader=None,
epochs=3000,
learning_rate=0.001,
model_param_path='ml_model1_params.h5',
auto_save=True,
continuation=True,
is_regression=False,
log_file='/tmp/train.log',)
T.show_img(mean_num=100) T.show_img_loss(mean_num=100) |
import torch
from torch import nn
import torch.nn.functional as F
import numpy as np
from tpf import T
from sklearn.datasets import make_classification
# torch 批次处理
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
from sklearn.datasets import make_regression
class MyDataSet(Dataset):
def __init__(self,X,y):
"""
构建数据集
"""
self.X = X
self.y = y
def __len__(self):
return len(self.X)
def __getitem__(self, idx):
x = self.X[idx]
y = self.y[idx]
return torch.tensor(data=x).float(), torch.tensor(data=y).long()
from tpf import pkl_load,pkl_save
import os
save_path = "datset1.pkl"
if os.path.exists(save_path):
X_1,y_1 = pkl_load( file_path=save_path, use_joblib=False)
else:
X_1,y_1 = make_classification(n_samples=100000,n_features=100,n_classes=2,)
pkl_save((X_1,y_1), file_path=save_path, use_joblib=False)
def get_train():
train_index = np.random.randint(low=0,high=100000,size=1000)
_X = X_1[train_index]
_y = y_1[train_index]
return MyDataSet(_X,_y)
def get_test():
test_index = np.random.randint(low=0,high=100000,size=200)
_X = X_1[test_index]
_y = y_1[test_index]
return MyDataSet(_X,_y)
这里先生成一份数据保存,后续每次加载的是相同的数据
取的时候,是随机取,对应现实数据集不全的场景
- 将取数据的方式以方法封装
- 每次调用方法,生成的数据集是不一样的
- 但都是全体数据集中的一部分
|
class DLModel(nn.Module):
"""模型定义
"""
def __init__(self, in_features, out_features):
"""参数网络设计
- 总体来说,做的事件是将数据从一个维度转换到另外一个维度
"""
super(DLModel, self).__init__()
self.linear = nn.Linear(in_features=in_features, out_features=out_features)
def forward(self, X):
"""正向传播
- 调用定义的参数网络
- 让数据流过参数网络,常量数据流过不过的参数产生不同的值
- 这个过程参数本身不会变
- 让参数变化的是后面的优化器
"""
out = self.linear(X)
return out
model = DLModel(in_features=100, out_features=2) loss_fn = torch.nn.CrossEntropyLoss() |
T.train(model,
loss_fn,
optimizer='sgd',
train_dataset_func=get_train,
test_dataset_func=get_test,
train_dataset=None,
test_dataset=None,
train_dataloader=None,
epochs=500,
learning_rate=0.001,
model_param_path='ml_model1_params.h5',
auto_save=True,
continuation=True,
is_regression=False,
log_file='/tmp/train.log',)
model_param_path='ml_model1_params.h5'
- 文件路径参数,默认当前文件所在目录
- 默认以ml_为开头,这样生成的文件在查看时,能显示在一块
|
T.show_img(mean_num=2) mean_num=2 - 如果轮次太多,图形会显得很密集 - mean_num取指定长度的数据取均值
每20个长度的数据取平均,图形会显得平滑易观 # 数据还是存在文件中的那份数据,只是显示的时候,以不同的方式显示 T.show_img(mean_num=20)
T.show_img_loss(mean_num=10)
T.show_img_test()
T.show_img_train()
|
#### 精度不再变化
- 反复检查,代码没有错误
- 训练集与测试集没有找乱,同一批次的数据,即相同的数据,得到的结果相同
- 因此预测精度不变了
- 根本原因是,针对一条固定的数据,模型预测的很稳定,就是一个稳定的结果
- 每条数据是这样,那么整体的结果也不会变
- 出现这种情况的几种可能
- 代码错误,也是最大的可能
- 数据集简单,数据不多;或者数据很多,每你每次用的很少;并且总用固定的一部分
- 如果一切都OK,数据集也够,那就是模型简单,或者说训练到了再也不会变化的地步了
- 反观本例,是模型太简单了,就是一个全连接
本次出现预测分数固定的原因是: - 取了相对固定的一部分数据集 - 模型也简单,训练也充分了,对于相对固定的数据集出现了固定的结果 解决方案: - 已经制定了随机取数据集的方法 - 每放在的轮次for循环的外面,将之移入for循环中就好了 |
|
振荡的训练结果
昨天训练的精度在90%左右,
今天开始之后一直在80%左右,怎么都不会升了
- 加大训练次数,基本没有变化
删除所有记录结果,让参数重新初始化
- 很快精度就又恢复到了90%左右
参数随机初始化后,优化前进的方向有很多个
- 随机选择一个
- 有些方向能走的远
- 有些方向注定不会走太远
总结
可尝试多从开始训练几次
注意将训练的结果保存移走,防止被覆盖
|
保存: def pkl_save(data, file_path, use_joblib=False, compress=0)
from tpf import pkl_load,pkl_save
pkl_save((model,loss),file_path=save_path, use_joblib=True)
pickle与joblib区别并不大, 只是深度学习模型转onnx时,只认joblib,所以模型保存就倾向于joblib吧 joblib - 可保存一切python对象,当然也包括 模型 - 对象序列化后写入文件 - 读取文件序列,反序列化转为对象
加载
from tpf import pkl_load,pkl_save model,loss=pkl_load(file_path=save_path, use_joblib=True) y_pred_dtr = model.predict(X_test) ((y_pred_dtr - y_test)**2).mean()
最大的可能是每次训练及预测的数据集不一样
数据集理论上要包含要学习的所有规律,是一个范围内规则的全集
但实际上,用到的数据集很难包括一个业务的所有规则
都是包括了一部分,大量的重复数据
学到的不一样,预测的也就有差异
当数据量足够大,大到包含了所有要学的规则时,
随意取一部分数据集都会包含所有要学的规则,
就算训练集不一样,相同的预测集结果也会非常接近
也有可能是在取数据集时,每次都是打乱了重新取 顺序不同,结果也有可能不同;关于顺序,也得看用的算法是不是与顺序无关
在深度学习中,模型参数是随机初始化的,
在不同的训练轮次中,结果不一样,
深度学习是随机一个起点,然后向最优解靠拢,
也有可能最优解有多少,靠拢到的最解角不同