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; } } }View Code
託管類,對應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("裝置控制服務關閉"); } } }View Code
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(); } } }View Code
另外需要注意的是Win服務編譯時需要選擇AnyCpu ,使用x86時發現報錯
最後對一部資料進行測試發現擬合效果還可以,多數差異在1%以內
上面程式碼基本就是全部了,需要完整專案留