- 积分
- 111
好友
记录
日志
相册
回帖0
主题
分享
精华
威望 旺
钢镚 分
推荐 人
|
本帖最后由 tsinfneg 于 2023-5-17 18:02 编辑
. i f# i: G0 h9 j2 W; S D, k/ a% H" e/ _6 c
以下是我为目前工作写的程序中,pytorch神经网络LSTM模型部分的主要代码。
3 f) r# b, F8 l6 d3 a'''torch 机器学习'''* K* [0 R+ ~* T* y" B
# 定义预测
' F( l+ F" I: c4 z' pclass Predict():
/ u: B0 ^* {, Q( J6 i& N # data 数据列表,n_steps数据分割步长
( V9 w6 h0 `" |3 K5 f def __init__(self,data,n_steps):7 m* Q( W8 T* p; ]! N* E! B @
self.data = data
, f, G7 G; o" K' _( q. S self.n_steps = n_steps6 v% G& ?! W* Q" h
( c$ A& l. B' i6 A0 U k # 序列分割,
, g @8 ?5 R: H0 ]" G9 w def split_df(self):/ g& K# U- R& I( C
X, y = list(), list()% j1 X- {+ l x+ m1 ?, ?$ x
for i in range(len(self.data)):! |0 f5 x) H* D* A; V3 w
# 确定最后一个分段
, n0 E$ R' X1 {4 s9 w end_ix = i + self.n_steps
0 Y+ F% W# |6 A( L4 s# c # 确定分段结束" J) I. T; F( T9 I
if end_ix > len(self.data)-1:
* K1 P& K/ s8 z; u break
1 f; \/ r( g9 t4 i, l3 H/ B- B # 开始分段,x为分段中各个元素,y为每个分段后的第一个元素* S- h/ F. k0 Y9 N& f0 x# B
seq_x = self.data[i:end_ix]4 T9 |" N4 G" X/ I% u
seq_y = self.data[end_ix]& N4 w% n0 ^4 y
X.append(seq_x)) H* U: v# S& p
y.append(seq_y)
$ O& |# c3 a) A; q. B return array(X), array(y)
1 l4 p: n' F$ Q' v& B3 L9 u & x: o/ x; e6 V
4 ]+ D$ \( e4 W- K; q8 u& {
0 m0 `" R6 R- s- l2 T
7 {; C9 C! y7 s9 {; @# 定义模型) n0 @% n+ O+ W$ ^' h
class LSTM(nn.Module):1 Q; D( u- }2 V
"""/ K& c; t* [+ u X
input_dim: 数据的特征数
# D U$ i: r9 H$ A hidden_dim:隐藏层神经元个数; e. L+ |' [1 U
num_layers:LSTM的层数9 ~, A8 s* m0 D; [7 l5 V
output_dim:预测的特征数 0 R0 ^- U# d) `9 }- [' q; X
"""( f! o; z- o6 W! d @6 W
def __init__(self, input_dim,hidden_dim, num_layers, output_dim):6 j! t1 H m, q2 _& q- p/ ^
super(LSTM, self).__init__()
, x' u8 r, y2 i7 s self.input_dim = input_dim
4 }$ W$ L; B% J; t { self.hidden_dim = hidden_dim
& v- H% p' \" ~: } self.num_layers = num_layers
# ?4 ]" C4 u4 {9 ]. A$ a
; O8 {8 u2 H3 m' w # 实例化模型,batch_frist = True表明输入格式为(batch, seq_dim, feature_dim)
) _. y5 g: Y9 ]# H% G- n7 y# P* E self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers, batch_first = True)
2 Z/ r/ `' Z% F4 _' J- O # 在LSTM后再增加一个全链接层,由于是回归,所以不能在线性层后增加激活函数,作用是加入长短期结果对新结果影响度的权重。& ?9 e6 D* x$ z6 q* r H
self.fc = nn.Linear(hidden_dim, output_dim)
z' U5 x5 t. T+ E2 `, h) ]0 i& a* ~! Q/ ~: ^
5 E% @3 M( }+ K* H8 t def forward(self, x):
, z9 y% Q" l$ H6 Z # 初始化的隐藏元和记忆元,通常它们的维度是一样的,设定初始的隐藏层为0,x(0)就是batch_size2 m$ p) n, B( E7 q0 H3 G
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_dim).requires_grad_()& B3 d& k |2 m
# $ Q( ~9 X0 s/ @* @5 h
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_dim).requires_grad_()
, z: P6 v$ b. L% u$ l/ Y # hn,cn是所有层最后一个隐藏元和记忆元的输出 ]" v A8 u. y2 V! x
out, (hn, cn) = self.lstm(x, (h0.detach(), c0.detach()))$ z# Q$ D S; }
# 用全链接层处理
8 g6 c1 W! `& W5 X out = self.fc(out)2 d! ~7 `" o7 l
return out
3 }" ^8 b; l( }7 r7 ]# g / Q4 E% s1 I. T9 @& K6 W
# 定义对未知的预测方法,x为预测天数。
+ A0 r- l- h: S9 J- f. D def predict(self,samples,x,model):# Z* F8 I6 O2 M: ~- z" L6 \* x
# 生成一个空序列用于存放结果
# C9 M" m5 B( X' Y _1 ? results = []/ L! q- b3 h/ h: C; {; x
for i in range(x):# X2 ~4 j9 J3 C
# l; x8 k; C9 p7 _; ~6 J3 W # # 使用最后一组数据预测一个新数据
. k1 X1 |# a! W% _! f N$ R0 ? result = model(samples[-1].reshape(-1,1,self.input_dim))
- p% G. ?( L7 _1 }" q # 转换结果格式,方便数据拼接
. s4 T d! @: P# Y, X result = result.detach().numpy()[:,-1,0]
# R7 D5 M' j( Y2 v, e! d+ y4 O2 y) d # 将结果定稿空序列
) F4 f! `( y6 h" B- g: X+ X results.append(result)8 [) y$ ?% P4 T) o
# 更改最后一组数据格式,用于拼接4 H ~% [7 W, L4 S) h- x" ?
a = samples[-1].detach().numpy()
7 Z2 \6 @. V6 a7 I5 @ a = a.reshape(self.input_dim)
6 r6 z V1 H y, v! X9 E # 取最后一组数据后4个元素,加上新预测的结果,组成新的计算数据6 t& w2 x1 w5 t7 Q8 p
sample = np.append(a[1:],result)
6 B) U+ @4 O; u6 \; [ # 整理数据格式 T: R, s# M* X6 u+ A1 t
sample = sample.reshape((1,1,self.input_dim))
" o6 \# L$ S) x- n# u samples1 = np.concatenate((samples,sample),axis=0)) Y/ c. a" B: `% T! q" e
samples = torch.from_numpy(samples1)9 w. q5 V. C, ^, v* \: y
4 L$ h' M- A# D- l% a- b+ k1 L2 V
# X1 = np.concatenate((samples,sample),axis=0)
6 D) E0 g+ m, Z. J5 W7 T # D0 _$ \% i% t6 Q5 H, H1 \
return samples
" g- C/ V" Q% V- L; c $ |5 D# F4 G: m! j4 w- y# P6 [
# 机器学习数据准备
! ]4 [3 P y% h# Jdef data_std(df,input_dim):
& t7 m: L; ?2 T1 v. C/ ?5 m5 _ # 数据准备, w2 P9 B' q) O, `
df1 = df[["检测日期","比例(%)"]]
% n; R( p+ q6 G #df = df.set_index("检测日期")* v; t* }) v4 m7 \9 w' ], V
df1["比例(%)"] = df1["比例(%)"].astype(np.float32)
) b( x0 t! f/ m data = df1["比例(%)"].tolist()
5 d, n0 V, C: U/ e0 I& U # 按步长划分数据
& `3 b5 T! ?, s2 U: Z lstm = pytorchlstm.Predict(data,input_dim)
& m/ K; }* a8 }9 R- ?" q, D X, y = lstm.split_df()
( D/ h2 I% \7 a, E$ f3 D X = X.astype(np.float32)
, K+ N; X8 d: p9 O% o y = y.astype(np.float32)' n5 _' H0 X, J
1 h% R' v* H" n4 M
# 按pytorch要求变换数据格式
- \% D2 T! O2 r' c X = X.reshape(-1,1,input_dim)
* u. d' M4 b) g3 t9 c y = y.reshape(-1,1,1)5 B; Q5 U$ C8 _0 x$ h
X = torch.from_numpy(X)
* l8 }4 [$ o9 j2 p9 s2 F Y, s6 ? y = torch.from_numpy(y)
0 S# v% V! n" W8 b0 M+ w6 i6 ] return X,y3 G, @" R7 \/ V" ^. e
5 @8 @ v9 e: O- O3 F0 E: X% A2 [* j p5 H$ u
# 模型训练$ U8 C& m$ T7 M' g0 S7 ^
def model_train(X,y,input_dim,hidden_dim, num_layers, output_dim,num_epochs):. v) b3 e; P( D2 Z- l
; Q W2 B2 k- j+ W$ v# I3 T3 { # 建立损失函数和优化器
' H7 Y* U7 s4 z/ e2 o! S model = pytorchlstm.LSTM(input_dim,hidden_dim, num_layers, output_dim)
0 H( P/ o6 }) N5 I; ]( f # 设定loss_fn采用的是均方差" I! o5 o, U# s# X7 E
loss_fn = nn.MSELoss(reduction='mean')2 T' b c% H% N8 Z8 z3 w% O0 V
# 模型的学习率定为0.019 {# Q g# i; g& a t
optimiser = torch.optim.Adam(model.parameters(), lr=0.01)1 f; ^! Y+ A" G0 H% k' V' ` \
' b1 R" x9 v( h0 Y! M/ Y( m$ S
# 开始训练
% ? S7 t: T$ t9 N8 | # 设定一个空列表,用于传入每次循环的偏差
& Q( M u8 P( D3 D. h* U/ H4 y hist = np.zeros(num_epochs)) A |+ u" g$ y) A% d
for t in range(num_epochs):
) G1 K* d3 d% i2 C5 m& n( T. k. l' M6 c, n # Initialise hidden state- e# \# i- K( m4 n) u
# Don't do this if you want your LSTM to be stateful
0 d2 v( Y3 {) ^5 l8 _ # model.hidden = model.init_hidden()- V7 X2 w( C* `/ q* b- e. L4 I5 e
7 B- C, ]7 z( A) F" ~1 N # Forward pass% L) ^. c& g- ~3 Y" p3 A
) R, o' s& V8 A+ L # 将梯度归零
6 k9 {/ a$ _/ d* M optimiser.zero_grad()
3 t. i0 f( w- `( L( R7 P N+ j# e1 F3 p+ u
# 前向传播计算5 {5 ]* C% h7 M) L
y_pred = model(X)2 ]2 @4 r' L( J/ L8 m
# 计算损失偏差,在前面已经设定loss_fn采用的是均方差9 Y: i8 ^9 ~# `8 l( ~* s9 i
loss = loss_fn(y_pred, y)
& j3 @9 F4 w% i9 F # 每训练一百次,打印一次均方差
# j" ~& p# ?/ a5 M T1 |9 k' U if t % 100 == 0 and t !=0: 9 O a6 \4 s$ |3 W! {' y( x
print("Epoch ", t, "MSE: ", loss.item())" D* N+ J* X' P+ m
# 将本次循环的均方差的值传入空列表) B; U2 q3 ~. E8 Z& w. q
hist[t] = loss.item()
2 F0 S$ H/ d4 o5 ?, \5 j# A
" ^- G( |, X) J, y, [ 5 {7 g$ t9 P! h6 q& h0 M7 \
# 将偏差回传,用于调整各层各节点参数3 L0 _ i) |6 l& O
loss.backward(), k3 U" _- A x6 c$ ~1 b, m- d9 Y9 P. y
' P3 c1 x( d9 }. `! S, C* ^; P
# 更新权重参数。, L- G; B" t$ n, Q F
optimiser.step()
7 X6 g7 p6 m+ J. m. w" L8 P% T5 `# q3 m) X
# 最终的偏差值
, X! g5 ?9 R0 k% n, _; x, a loss = loss_fn(y_pred, y).item()7 O. y, C$ S/ r& y; k3 j4 z1 ]
# plt.plot(range(num_epochs),hist)) l3 e; i4 l/ d+ v; N3 A: {
# plt.show()) f" ^8 ~" \( S/ `6 Q
print(loss)
! l+ o- z' {% K/ m) x: i/ P9 o! Z3 w: t2 _* F6 `3 K
# 保存模型
5 C0 o) I- I$ q6 ?& _; ] torch.save(model, "model/torch_model0504.pth") J$ \5 N' }8 }6 i. q& |
+ x @8 e0 c8 l& e3 e( \, ?8 A# 数据预测
. p% a+ ] |+ F% m" Y( D6 F* l! R1 idef pred(input_dim,X,y,pre):- M: d/ ]$ V1 M I( U- ?! c2 ^
## 读取模型
: m, q6 G- Q& X' U model = torch.load('model/torch_model0504.pth')* d3 c6 I% K9 Y8 S
# 预测. a8 q& x& l Y6 G# g
samples = X
. t% z; b8 e$ K" w # 生成一个空序列用于存放结果
( x3 f$ B# i- t results = []
# T+ K9 O: K% m+ r5 _ for i in range(pre):! ~3 @7 S4 j. p( R i
: C0 b O" W) k% p5 [' @$ [
# 使用最后一组数据预测一个新数据4 x5 \% b# h8 H8 ?1 C
result = model(samples[-1].reshape(-1,1,input_dim))
. R- f7 }; s) m # 转换结果格式,方便数据拼接8 c, E0 ~/ g. P: D( A5 ~
result = result.detach().numpy()[:,-1,0]. U1 J2 \$ Q6 r1 u) ]7 D: ]
# 将结果定稿空序列
1 i7 C% t2 { t; t5 d5 d: j5 [; O results.append(result)
* v' {# {1 R& f* R# t # 更改最后一组数据格式,用于拼接 C! ?* e1 [- d
a = samples[-1].detach().numpy()5 b/ e! V; |1 I8 b. Q1 {2 d
a = a.reshape(input_dim)8 e9 m6 Z, r! o5 [& i j8 c2 g
# 取最后一组数据后4个元素,加上新预测的结果,组成新的计算数据% `3 J- U; g2 I4 z+ X( G
sample = np.append(a[1:],result)
3 r2 ?. a! s, L- s # 整理数据格式便于循环输入模型8 a. Z4 N* ~9 u" U* W3 _
sample = sample.reshape((1,1,input_dim)) f' b) p" s( ?) e9 L, B. o
samples1 = np.concatenate((samples,sample),axis=0)
, ^& l4 s; f3 D+ R) ^- f samples = torch.from_numpy(samples1): t. P3 [1 T. l2 a7 ^' t
$ @% Y/ D S: e2 t- L4 E2 S+ y
& {4 N4 X& I2 Z6 z+ N' F/ p* i
# 对已有数据进行计算
" W( n$ Y" L+ }2 F y_pred = model(samples.reshape(-1,1,input_dim))
0 J) g7 k# u4 \7 n) B
2 }, s- W% I' `% P # 将结果由torch格式转换为numpy格式
2 P9 W; _6 _2 d/ j2 l a/ y pred_value = y_pred.detach().numpy()[:,-1,0]2 f+ [# \$ Q1 }
# 将训练用的y由torch格式转换为numpy格式。方便plt绘图,分析模型质量
3 j) G' R/ i' H6 Z) X true_value = y.detach().numpy()[:,-1,0] % W' C% l, c+ \* J& k
+ I$ B' j$ J3 T9 U- ?+ G4 Z9 U # pred_value1 = np.append(pred_value, results)
3 a; f' C: \3 X& S) j
. a$ H" v$ c& L pred_value1 = pred_value% H6 C0 ]. p7 G, R& o! C; I/ }5 O
return pred_value1 |
|