3.3.1 Xác định yêu cầu
Thiết kế mô hình có thể đưa ra dự báo nhiệt độ trong vòng 1 giờ tiếp theo, mục đích là để đề phòng hiện tượng biến chuyển nhiệt độ đột ngột trong môi trường ao hồ từđó phát hiện và đưa ra cảnh báo tới người dùng nhằm có biện pháp điều chỉnh kịp thờị
3.3.2 Xây dựng mô hình LSTM để dự báo nhiệt độ
Qua nghiên cứu một số tài liệu tham khảo và kinh nghiệm thực tiễn, tác giả đã lựa chọn số nơ-ron lớp ẩn và các tham số cấu hình cho mô hình dự báo tham số nhiệt độnhư sau:
- Số lần lặp tối đa (epoch): 100 - Hằng số học (learning rate): 0.05 - Sốlượng neuron ẩn thử từ: 60 -> 120
- Xác xuất tắt neuron (drop out): [0.1, 0.2, 0.3, 0.4, 0.5]
- Hàm kích hoạt: ReLU
- Đánh giá model bằng công thức: Sai số trung bình, sai số lớn nhất, sai số nhỏ nhất, phạm vi sai số, phương sai, độ lệch chuẩn.
- Mô hình được đào tạo với phương pháp tối ưu Adam và hàm lỗi là sai số bình phương trung bình.
- Quá trình huấn luyện thực hiện trên hề điều hành win10, CPU: Intel(R) Core(TM) i5-5200U CPU 2.20 GHz, RAM: 8GB
Bảng 3.1: Thống kê các sai số của các dropout khác nhau
Thời gian đào tạo (Giây) Sai số trung bình Sai số lớn nhất Sai số nhỏ nhất Phạm vi
sai số Phương sai
Độ lệch chuẩn Dropout = 0.1 70.82 0.40480 3.38621 0.00014 3.38606 0.16932 0.8233 Dropout = 0.2 64.25 0.42370 3.72840 0.00017 3.72824 0.16054 0.41149 Dropout = 0.3 69.30 0.46028 3.59984 0.00024 0.163202 0.40398 0.8233 Dropout = 0.4 71.69 1.95628 5.66351 0.00157 5.6619 1.32126 1.14946 Dropout = 0.5 74.83 1.1420 4.5227 0.0003 0.610987 0.78165 0.8233
57 Từ kết quả bảng Thống kê các sai số của các drop out khác nhau (Bảng 3.1), lựa chọn dropout = 0.1. áp dụng vào dự báo tham số nhiệt độ.
Kết quả mô hình này với tham số nhiệt độ được thể hiện trong Bảng 3.2 và Hình 3.6.
Bảng 3.2: Kết quả kiểm tra mô hình LSTM thực hiện đối với tham số Nhiệt độ
Sai số trung bình Sai số lớn nhất Sai số nhỏ nhất Phạm vi
sai số Phương sai
Độ lệch chuẩn Nhiệt độ 0.4237 3.7284 0.0002 3.7282 0.1605 0.4007
Hình 3.6: So sánh kết quả dự báo nhiệt độ sử dụng mô hình LSTM với giá trị đo thực tế
LSTM_model = Sequential()
LSTM_model.ađ(LSTM(units=60,activation='relú,return_sequen ces = True, input_shape = (X_train.shape[1], 1))
LSTM_model.ađ(Dropout(0.2)) LSTM_model.ađ(LSTM(units=60,activation='relú,return_sequen ces = True)) LSTM_model.ađ(Dropout(0.2)) LSTM_model.ađ(LSTM(units=80,activation='relú,return_sequen ces = True)) LSTM_model.ađ(Dropout(0.2))
LSTM_model.ađ(LSTM(units = 120, activation = 'relú)) LSTM_model.ađ(Dropout(0.2))
LSTM_model.ađ(Dense(units = 1))
3.3.3 Xây dựng mô hình SimpleRNN để dự báo nhiệt độ
Trong mô hình SimpleRNN giữ nguyên kiến trúc 4 lớp hồi tiếp như mô hình LSTM thì kết quả chênh lệch khá nhiều so với kết quả dự báo của mô hình LSTM. Kết quả của mô hình này được thể hiện trong Bảng 3.3 và Hình 3.7.
Bảng 3.3: Kết quả kiểm tra mô hình SimpleRNN thực hiện đối với tham số Nhiệt độ
Sai số trung bình Sai số lớn nhất Sai số nhỏ nhất Phạm vi
sai số Phương sai
Độ lệch chuẩn
58
Hình 3.7: So sánh kết quả dự báo nhiệt độ sử dụng mô hình SimpleRNN với giá trị đo thực tế
Tương tựkhi thay đổi kiến trúc mô hình SimpleRNN thành 2 lớp hồi tiếp, bỏđi 2 lớp cuối trong mô hình trên. Lớp đầu tiên và thứ2 đều có 60 nút. Kết quả dự báo của mô hình được cải thiện tuy nhiên vẫn không thể chính xác được so với mô hình LSTM (Bảng 3.4).
Bảng 3.4: Kết quả kiểm tra mô hình SimpleRNN 2 lớp đối với tham số Nhiệt độ
Sai số trung bình Sai số lớn nhất Sai số nhỏ nhất Phạm vi
sai số Phương sai
Độ lệch chuẩn Nhiệt độ 0.9320 5.0658 0.0002 5.0641 0.3374 0.6113
3.3.4 Xây dựng mô hình GRU để dự báo nhiệt độ
Mô hình GRU được xây dưng với kiến trúc và phương pháp đào tạo như mô hình LSTM. Kết quả kiểm thử của mô hình được thể hiện trên Bảng 3.5 và Hình 3.8.
Bảng 3.5: Kết quả kiểm tra mô hình GRU thực hiện đối với tham số Nhiệt độ
Sai số trung bình Sai số lớn nhất Sai số nhỏ nhất Phạm vi
sai số Phương sai
Độ lệch chuẩn Nhiệt độ 0.8475 4.1915 0.0001 4.1913 0.3520 0.5933
59
3.4 Triển khai thực hiện trên server 3.4.1 Chuẩn bị dữ liệu 3.4.1 Chuẩn bị dữ liệu
Sử dụng 60 điểm dữ liệu làm đầu vào để dựđoán cho điểm thứ61. Các thư viện cần thiết cho bước tiền xử lý là:
import matplotlib.pyplot as plt import numpy as np
import pandas
from sklearn.preprocessing import MinMaxScaler
Hàm read_csvđược sử dụng để tải dữ liệụ concat được sử dụng để ghép nối dữ liệụ Sau khi tải và ghép nối dữ liệu, dữ liệu được hiển thị 5 hàng cuối cùng của bộ dữ liệu bằng hàm datạtail(). Bộ dữ liệu để đào tạo bắt đầu từ
06h00 05/02/2019 đến 00h00 ngày 09/10/2019.
thang_2=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/2.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_3=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/3.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_4=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/4.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_5=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/5.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_6=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/6.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_7=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/7.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_8=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/8.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_9=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/9.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
60
luan van/Final/Thu_nghiem_du_lieu/2019/10.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
nam_2019=pandas.concat([thang_2,thang_3,thang_4,thang_5,than g_6,thang_7,thang_8,thang_9, thang_10])
nam_2019.tail()
Dữ liệu sau khi được tải, sẽ được làm sạch bằng cách loại bỏ các cột không cần thiết là Date và Hour, điều chỉnh dữ liệu lại trong khoảng [0, 1] bằng cách sử dụng MinMaxScaler(). Điều này nhằm cải thiện hiệu suất dựđoán.
data_training = nam_2019.copy().drop(['Daté, 'Hour'], axis=1)
scaler = MinMaxScaler()
data_training = scaler.fit_transform(data_training) data_training
Dữ liệu sau khi đã điều chỉnh (Hình 3.9).
Hình 3.9: Kết quả dữ liệu sau khi điều chỉnh
Dữ liệu được chia thành X_train và y_train đảm bảo cho 60 điểm đầu vào dự báo 1 điểm đầu ra (điểm thứ 61).
X_train = [] y_train = []
for i in range(60, data_training.shape[0]): X_train.append(data_training[i-60:i]) y_train.append(data_training[i, 0])
X_train, y_train = np.array(X_train), np.array(y_train)
Làm tương tự như vậy với bộ dữ liệu kiểm thử. Bộ dữ liệu kiểm thử bắt đầu từ 06h00 09/10/2019 đến 12h00 ngày 16/12/2019.
61
3.4.2 Xây dựng mô hình
Như đã trình bày phần trước, mô hình được lựa chọn là mô hình Long Short Term Memory (LSTM). Từ mô hình đó việc triển khai áp dụng mô hình trên server được thực hiện như sau:
LSTM_model = Sequential()
LSTM_model.ađ(LSTM(units = 60, activation = 'relú, return_sequences=True,input_shape = (X_train.shape[1], 1))) LSTM_model.ađ(Dropout(0.1))
LSTM_model.ađ(LSTM(units = 60, activation = 'relú, return_sequences = True))
LSTM_model.ađ(Dropout(0.1))
LSTM_model.ađ(LSTM(units = 80, activation = 'relú, return_sequences = True))
LSTM_model.ađ(Dropout(0.1))
LSTM_model.ađ(LSTM(units = 120, activation = 'relú)) LSTM_model.ađ(Dropout(0.1))
LSTM_model.ađ(Dense(units = 1))
Bằng cách sử dụng lệnh model.summary() nó sẽ hiện mô tả ngắn gọn các lớp và cấu trúc đầu ra, và sốlượng các tham số tầng lớp (Hình 3.10):
62 Sốlượng tham sốnày được tính như sau:
- Đối với LSTM, thì thì số lượng tham số là: 4 × (inputsize + outputsize + 1)* inputsize;
- Đối với lớp kết nối đầy đủ (Dense layer hay fully-connected layer) thì số lượng tham số là: outputsize × (inputsize + 1)
Trong đó:
- inputsize là kích thước đầu vào của lớp đó. - outputsize là kích thước đầu ra của lớp đó.
3.4.3 Đào tạo và lưu lại mô hình
Sau khi xây dựng mô hình, mô hình được đào tạo với thuật toán tối ưu là Adam và hàm lỗi là sai số bình phương trung bình với epochs = 50 và batch_size = 32 là 2 lựa chọn phổ biến nhất. Đối với những mẫu có kích thước nhỏ, đa số lời khuyên sẽ là batch_size là 32 hoặc 25.
LSTM_model.compile(optimizer='adam', loss='mean_squared_error')
LSTM_model.fit(X_train,y_train, epochs=50, batch_size=32)
Sau quá trình đào tạo, mô hình được lưu lại để có thể sử dụng sau này:
LSTM_model.save('LSTM_model.h5')
Kết quảsau khi được lưu lại sẽ tái sử dụng để dựđoán bằng cách gọi hàm:
load_model
3.4.4 Xây dựng cách kiểm thử mô hình và đánh giá
Với việc phân chia đầu vào và đầu ra nhưở trên, ta có dữ liệu để kiểm thử là ma trận 2 chiều X_test và ma trận 1 chiều y_test. Đối với tham số nhiệt độ, bộ dữ liệu kiểm thử X_test và y_test là có độ dài là 2916. Đối với 6 tham số khác, bộ dữ liệu kiểm thửX_test và y_test có độ dài là 411.
Sau khi phân chia dữ liệu, X_test được đưa vào mô hình để dựđoán:
y_pred = LSTM_model.predict(X_test)
Vì kết quả X_test đã được điều chỉnh, nên kết quả dự báo cũng sẽ nằm trong khoảng 0 đến 1, vì vậy cần chuyển kết quả dự báo về dạng ban đầụ
y_pred = scaler.inverse_transform(y_pred)
63 - Vẽ cả kết quả dự báo và kết quả thực tế trên cùng 1 đồ thị để có
cách nhìn trực quan nhất.
- Thống kê lại sự chênh lệch bằng cách lấy |y_test - y_pred|. Kết quả thống kê sự chênh lệch được tổng hợp, tính toán và vẽ đồ thị phân phối tích lũy sai số
64
CHƯƠNG 4.TRIỂN KHAI THỰC HIỆN TRÊN MOBILE
Nhằm giúp cho các hộ dân nuôi tôm có cái nhìn trực quan về sự thay đổi của các tham số nguồn nước, đềtài đã sử dụng các mẫu đồ thị để biểu diễn tham sốtrên điện thoại di động.
4.1 Lựa chọn thư viện đồ thị
Từ các giao diện đồ thị đã tìm hiểu, nhóm nghiên cứu đã lựa chọn thư viện MPAndroidChart để tạo ra các mẫu đồ thị tham số cho ứng dụng do sựđơn giản nhưng phù hợp về mặt thẩm mỹ. Về mặt triển khai lập trình thì thư viện cũng hỗ trợ nhiều, làm đơn giản hóa quá trình lập trình.
4.1.1 Thư viện MPAndroidChart
• Đặc điểm
Đây là một thư viện mạnh mẽ và dễ dàng sử dụng để vẽcác đồ thị trên hệđiều hành Android.
Có phiên bản thư viện khác trên hệđiều hành iOS là Charts
Hỗ trợ các giải pháp vẽ đồ thị realtime (thời gian thực) thông qua SciChart
Hỗ trợ tất cả các loại biểu đồ
• Lựa chọn loại đồ thị
Do mục đích của việc vẽ các mẫu đồ thị là giúp người dùng có thể dễ dàng quan sát các mẫu tham số nguồn nước nên nhóm nghiên cứu đã lựa chọn loại đồ thị dạng đường LineChart phục vụ cho ứng dụng của mình.
• Triển khai vẽđồ thị trong lập trình Tạo LineChart trong file .xml
Ánh xạ LineChart từ file .xml sang code
65 Thêm List<Entry> vào đối tượng LineDataSet
Thêm đối tượng LineDataSet vào đối tượng LineData
4.1.2 Phát triển mẫu đồ thị biểu diễn tham số
4.1.2.1. Thiết kế đồ thị biểu diễn tham số
Sau khi đã chọn được loại đồ thị cần sử dụng, tiếp theo tới việc thiết kế các giao diện biểu diễn các đồ thị của các tham số nguồn nước. Nhóm nghiên cứu thiết kế các đồ thị bao gồm các thành phần cấu thành như sau:
• Tên đồ thị biểu diễn tham số
• Đồ thị biểu diễn tham số: trong đồ thị bao gồm ba đường gồm có đường biểu diễn ngưỡng cực đại của tham số, đường biểu diễn ngưỡng cực tiểu của tham sốvà đường biểu diễn giá trị tham số thực tếđo được.
66 Trên Hình 4.1 là đồ thị biểu diễn tham số pH trong đó đường màu đỏ là đường thể hiện ngưỡng giá trị cực đại của tham số (High Warning), đường màu vàng là đường thể hiện ngưỡng giá trị cực tiểu của tham số (Low Waring) và đường màu xanh là đường thể hiện giá trị đo được thực tế (Current). Với các đồ thị của tham sốkhác cũng tương tựnhư vậỵ Màu của các đường biểu diễn có thể được thay đổi theo hệ điều hành Android hay iOS cho phù hợp với giao diện người dùng.
4.1.3 Thiết kế giao diện biểu diễn đồ thị
Các đồ thị biểu diễn các tham số sẽđược hiển thị trên giao diện ứng dụng có thể theo dạng danh sách trên hệđiều hành Android (Hình 4.2).
Hình 4.2: Giao diện biểu diễn đồ thị trên Android
4.1.4 Thiết kế các bước thực hiện
Về mặt thuật toán để hiển thị các giá trị tham sốtrên đồ thị đề tài đã xây dựng sơ đồ khối tổng quát các bước vẽ đồ thị có sử dụng thư viện của MPAndroidChart và thư viện Retrofit do Google cung cấp – có sẵn các API giúp thuận tiện cho việc lập trình (Hình 4.3).
Khối thứ nhất Create list Entries and Labels với mục đích tạo các đầu vào trên đồ thịứng với trục tung Oy (trong MPAndroidChart gọi là các Entry) và các
67 nhãn ghi giá trị của điểm ứng với trục hoành Ox (trong MPAndroidChart gọi là các Label). Sau khi tạo được danh sách các Entries và Labels tiếp tục tạo ra danh sách đồ thị qua khối thứ hai Create list graph. Ở khối này, các Entries và Labels
sẽ được thêm vào các Graph tương ứng. Sau khối thứhai đầu ra thu được sẽ là danh sách các đồ thị trống chưa có dữ liệụ Đểcác đồ thị hiển thị các dữ liệu trên đó cần phải thực hiện việc lấy dữ liệu của các tham số nguồn nước (param) tương ứng với các thiết bị và các biểu đồ bằng khối thứ ba Get list data by param, sau đó thêm các dữ liệu đó vào các đồ thị trống bằng việc thực thi khối thứtư Ađ data to graphs.
Get list data by param Create list Entries and Labels
Create list graph
Ađ data to graphs
Update list graphs on UI
Hình 4.3: Sơ đồ khối tổng quát các bước vẽ đồ thị các tham số
Cuối cùng sau khi các đồ thịđã có dữ liệu, lúc này công việc cuối cùng là cập nhật lại danh sách đồ thị trên giao diện qua khối thứ năm Update list graph on UỊ
4.2 Triển khai trong lập trình
• Tạo đối tượng List Entries và List Labels
//All components of all graphs
private ArrayList<Entry> entriesPH=new ArrayList<>();
private ArrayList labelsPH = new ArrayList<String>();
private ArrayList<Entry> entriesSalt=new ArrayList<>();
private ArrayList labelsSalt = new ArrayList<String>();
private ArrayList<Entry> entriesOxy=new ArrayList<>();
68
private ArrayList<Entry> entriesTemp=new ArrayList<>();
private ArrayList labelsTemp = new ArrayList<String>();
private ArrayList<Entry> entriesH2S=new ArrayList<>();
private ArrayList labelsH2S = new ArrayList<String>();
private ArrayList<Entry> entriesNH3=new ArrayList<>();
private ArrayList labelsNH3 = new ArrayList<String>();
private ArrayList<Entry> entriesNH4Min=new ArrayList<>();
private ArrayList labelsNH4Min = new ArrayList<String>();
private ArrayList<Entry> entriesNH4Max=new ArrayList<>();
private ArrayList labelsNH4Max = new ArrayList<String>();
private ArrayList<Entry> entriesNO2Min=new ArrayList<>();
private ArrayList labelsNO2Min = new ArrayList<String>();
private ArrayList<Entry> entriesNO2Max=new ArrayList<>();
private ArrayList labelsNO2Max = new ArrayList<String>();
private ArrayList<Entry> entriesH2SMax=new ArrayList<>();
private ArrayList labelsH2SMax = new ArrayList<String>();
private ArrayList<Entry> entriesH2SMin=new ArrayList<>();
private ArrayList labelsH2SMin = new ArrayList<String>();
• Tạo danh sách biểu đồ
listGraph=new ArrayList<>();
Graph gPH=new Graph(arrLabels[0],entriesPH,labelsPH);
Graph gSalt=new Graph(arrLabels[1],entriesSalt,labelsSalt);
Graph gOxy=new Graph(arrLabels[2],entriesOxy,labelsOxy);
Graph gTemp=new Graph(arrLabels[3],entriesTemp,labelsTemp);
Graph gH2S=new Graph(arrLabels[4],entriesH2S,labelsH2S);
Graph gNH3=new Graph(arrLabels[5],entriesNH3,labelsNH3);
Graph gNH4Max=new
Graph(arrLabels[6],entriesNH4Max,labelsNH4Max);
Graph gNH4Min=new
Graph(arrLabels[7],entriesNH4Min,labelsNH4Min);
Graph gNO2Max=new
Graph(arrLabels[8],entriesNO2Min,labelsNO2Max);
Graph gNO2Min=new
Graph(arrLabels[9],entriesNO2Min,labelsNO2Min);
Graph gH2SMax=new
Graph(arrLabels[10],entriesH2SMax,labelsH2SMax);
69
Graph(arrLabels[11],entriesH2SMin,labelsH2SMin);
Graph [] arrGraph=new Graph[]{gPH,gSalt,gTemp,
gH2S,gH2SMax,gH2SMin,
for (Graph g:arrGraph){
listGraph.ađ(g);
}
• Lấy dữ liệu theo tham số và thêm dữ liệu vào đồ thị
//lay du lieu ung voi tung thong so
public void getDataThongKe(final int tempSelectThongSo) {
String urlThongKe = Constant.URL +
Constant.API_GET_DATA_PACKAGE + "date=" +
BieuDoActivity.tmpNgayThangNam +
"&deviceid=" + tmpSelectedDeviceId + "¶mid="
+ String.valueOf(tempSelectThongSo);
Uri builder = Uri.parse(urlThongKe)
.buildUpon()
.build();
downloadJSON = new DownloadJSON(getContext());
downloadJSON.GetJSONArray(builder, new
DownloadJSON.DownloadJSONCallBack() {
@Override
public void onSuccess(String msgData) {
try{
JSONArray jsonArray = new
JSONArray(msgData);
if(jsonArray.length()==0){
txtContent.setVisibility(View.VISIBLE);
}
else{
String
nameGraph=arr_thongso[tempSelectThongSo-1];