C# + Matlab 实现计件工时基于三层BP神经网络的拟合--真实项目
工序工时由该工序的工艺参数决定,有了工时后乘以固定因子就是计件工资。一般参考本地小时工资以及同类小时工资并考虑作业的风险等因素给出固定因子
采用的VS2010 , Matlab2015a 64, 开发端是win7 64 , 部署端是win2012 R2 Datacenter 64
Matlab部分
下面是样本数据:
注意样本数据要尽可能全面,比方这里会交换L与R后做为另一组样本数据一起交给系统训练
打钩的数据会抽取来训练,WTime是目标,所以5个输入1个输出。
训练代码
clc clear excel=xlsread('frmZJ_KB_SalaryParamAdmin2011140841.xls'); % 训练集——个样本 P_Train=excel(:,[4 5 11 7 8])'; %注意运算时需要转置矩阵 T_Train=excel(:,9)'; % 测试集——个样本 rndSample=randperm(size(excel,1),500); %随机选择100个作为样本 P_Test=P_Train(:,rndSample); T_Test=T_Train(:,rndSample); %% III. 数据归一化 [p_train, ps_input] = mapminmax(P_Train,0,1); p_test = mapminmax('apply',P_Test,ps_input); save('ps_input.mat','ps_input'); [t_train, ps_output] = mapminmax(T_Train,0,1); save('ps_output.mat','ps_output') N = size(P_Test,2); %% IV. BP神经网络创建、训练及仿真测试 %% % 1. 创建网络 net = newff(p_train,t_train,60); %% % 2. 设置训练参数 net.trainParam.epochs = 10000; net.trainParam.goal = 1e-5; net.trainParam.lr = 0.01; %% % 3. 训练网络 net = train(net,p_train,t_train); save('ZJPrediction.mat','net'); %% % 4. 仿真测试 t_sim = sim(net,p_test); %% % 5. 数据反归一化 T_sim = mapminmax('reverse',t_sim,ps_output); %% V. 性能评价 %% % 1. 相对误差error error = abs(T_sim - T_Test)./T_Test; %% % 2. 决定系数R^2 R2 = (N * sum(T_sim .* T_Test) - sum(T_sim) * sum(T_Test))^2 / ((N * sum((T_sim).^2) - (sum(T_sim))^2) * (N * sum((T_Test).^2) - (sum(T_Test))^2)); %% % 3. 结果对比 result = [T_Test' T_sim' error'] %% VI. 绘图 figure plot(1:N,T_Test,'b:*',1:N,T_sim,'r-o') legend('真实值','预测值') xlabel('预测样本') ylabel('输出值') string = {'测试集预测结果对比';['R^2=' num2str(R2)]}; title(string)
训练好的模型要保存起来,还有归一化参数,下面3个打钩的文件要发布到生产环境中
下面是需要封成dll的函数,里面采用了绝对路径,因为封装成Windows Service后matlab的工作目录会在C盘下的临时目录
function r=PredictionZJWTime(d) load('D:\MatlabServer\ps_input.mat','ps_input'); load('D:\MatlabServer\ps_output.mat','ps_output'); load('D:\MatlabServer\ZJPrediction.mat','net'); P_Test=d'; p_test = mapminmax('apply',P_Test,ps_input); %% % 4. 仿真测试 t_sim = sim(net,p_test); %% % 5. 数据反归一化 T_sim = mapminmax('reverse',t_sim,ps_output); r=[d T_sim' T_sim'*0.0062]; end
下面在matlab环境下测试所封装的函数
clc clear excel=xlsread('frmZJ_KB_SalaryParamAdmin2011120839.xls'); % 训练集——个样本 P_Train=excel(:,[4 5 11 7 8])'; %注意运算时需要转置矩阵 T_Train=excel(:,9)'; % 测试集——个样本 rndSample=randperm(size(excel,1),100); %随机选择100个作为样本 P_Test=P_Train(:,rndSample); T_Test=T_Train(:,rndSample); T_Sim=PredictionZJWTime(P_Test'); T_Sim(:,6) - T_Test'
生成dll库文件
生成的dll文件一般有2个文件。ZJSim与ZJSimNative,后面带Native是本地类库,调用参数有点区别--Class Name可自己修改
另外还要copy MWArry.dll文件 一般安装在 C:\Program Files\MATLAB\MATLAB Production Server\R2015a\toolbox\dotnetbuilder\bin\win64\v2.0\MWArray.dll
C#部分
分装成windows服务,并对外以WCF HttpBinding的方式发布, 本来想直接挂在IIS下,但是一直没调试成功
服务类
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple, MaxItemsInObjectGraph = 2147483647, IgnoreExtensionDataObject = true, UseSynchronizationContext = false)] public class HDMatlabServiceImp : IHDMatlabService { public List<ZJPredictionInfo> PredictionForZJ(List<ZJPredictionInfo> inData) { var inMatrix=new double[inData.Count,5]; for (int row=0;row<inData.Count;row++) { var it=inData[row]; inMatrix[row, 0] = it.L; inMatrix[row, 1] = it.R; inMatrix[row, 2] = it.D; inMatrix[row, 3] = it.I; inMatrix[row, 4] = it.S; //inMatrix[row, 5] = it.WTime; //inMatrix[row, 6] = it.SalaryPerUnit; } var srv = new ZJWTimeSimulater(); var outMatrix = (double[,])srv.PredictionZJWTime(inMatrix); for (int i = 0; i < inData.Count; i++) { inData[i].SimWTime = outMatrix[i, 5]; inData[i].SimSalaryPerUnit = outMatrix[i, 6]; } return inData; } } }
托管类,对应binging的配置方在app.config中貌似没反映,所以就整到代码里,
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Configuration; using HD.Matlab.IService; namespace HD.Matlab.Service { public class HDMatlabServiceHost { public static readonly HDMatlabServiceHost Instance = new HDMatlabServiceHost(); private HDMatlabServiceHost() { } private ServiceHost _Host; public void Start(params string[] args) { if (_Host == null || _Host.State == CommunicationState.Faulted || _Host.State == CommunicationState.Closed) { _Host = new ServiceHost(typeof(HDMatlabServiceImp)); //_Host.AddServiceEndpoint(typeof(IHDMatlabService), new NetTcpBinding(SecurityMode.None), // ConfigurationManager.AppSettings["HDMatlabServiceURL"] // ); var httpBing = new BasicHttpBinding(BasicHttpSecurityMode.None); httpBing.CloseTimeout = new TimeSpan(10, 10, 10); httpBing.MaxReceivedMessageSize = 2147483647; httpBing.MaxBufferSize = 2147483647; httpBing.MaxBufferPoolSize = 99999999; httpBing.ReaderQuotas.MaxArrayLength = 99999999; httpBing.OpenTimeout = new TimeSpan(10, 10, 10); httpBing.SendTimeout = new TimeSpan(10, 10, 10); httpBing.ReceiveTimeout = new TimeSpan(10, 10, 10); httpBing.AllowCookies = true; _Host.AddServiceEndpoint(typeof(IHDMatlabService), httpBing, ConfigurationManager.AppSettings["HDMatlabServiceURL_Http"] ); } _Host.Open(); Console.WriteLine("设备控制服务启动成功"); } public void Stop() { if (_Host != null) _Host.Close(); Console.WriteLine("设备控制服务关闭"); } } }
Windows服务
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.ServiceProcess; using System.Text; using HD.Matlab.Service; namespace HD.Matlab.WinSrv { public partial class MatlabService : ServiceBase { public MatlabService() { InitializeComponent(); } protected override void OnStart(string[] args) { HDMatlabServiceHost.Instance.Start(); } protected override void OnStop() { HDMatlabServiceHost.Instance.Stop(); } } }
另外需要注意的是Win服务编译时需要选择AnyCpu ,使用x86时发现报错
最后对一部数据进行测试发现拟合效果还可以,多数差异在1%以内
上面代码基本就是全部了,需要完整项目留邮箱