Julia使用transformer训练数据预测模子

打印 上一主题 下一主题

主题 1768|帖子 1768|积分 5304

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
一、使命描述
选取各检测设备工艺运行参数1534个。
每分钟记录1条数据。
根据1个小时的60条数据预测未来30分钟的30条数据。
二、模子描述
输入大小60*1534,输出大小30*1534
三、主要参数
输入长度in_len 60,输出长度out_len 30,特征值feature_dim1534,模子大小d_model64,头数n_head,编码层num_enc和解码层层数num_dec2
训练批次batch_size:32
四:代码
1、由于训练数据存储在多个csv文件里,因此使用增量方式计算均值和方差,方便进行数据的标准化
  1.     # 定义增量计算均值和标准差的函数
  2.     function online_mean_std!(μ::Vector{Float64}, σ::Vector{Float64}, n::Int, new_data::Matrix{Float64})
  3.         m = size(new_data, 2)  # 特征数量
  4.         if n == 0
  5.             # 初始时直接设置均值和标准差(注意这里 mean(new_data, dims=1) 得到的是 1×m 的数组,转换为向量)
  6.             μ .= vec(mean(new_data, dims=1))
  7.             σ .= vec(std(new_data, dims=1; corrected=false))
  8.             return size(new_data, 1)
  9.         end
  10.         for i in 1:size(new_data, 1)
  11.             n += 1
  12.             for j in 1:m
  13.                 delta = new_data[i, j] - μ[j]
  14.                 μ[j] += delta / n
  15.                 # 更新公式(非修正方差)
  16.                 σ[j] = sqrt(((n - 2) / (n - 1)) * (σ[j]^2) + (delta^2 / n))
  17.             end
  18.         end
  19.         return n
  20.     end
  21.     # 计算均值和标准差
  22.     function calc_mean_std(data_dir::String)
  23.         μ = Float64[]
  24.         σ = Float64[]
  25.         n = 0
  26.         csv_files = glob("data_*.csv", data_dir)
  27.         for file in csv_files
  28.             df = CSV.read(file, DataFrame)
  29.             # 删除两列,空数据列
  30.             select!(df, Not([:pn_y17zsl8001a, :pn_cbkg1003gxtt]))
  31.             data = Matrix(df)
  32.             if n == 0
  33.                 μ = zeros(size(data, 2))
  34.                 σ = zeros(size(data, 2))
  35.             end
  36.             n = online_mean_std!(μ, σ, n, data)
  37.         end
  38.         # 将计算得到的均值和标准差保存到磁盘
  39.         open(joinpath(Common.get_runtime_dir(), "../config/data_stats.jls"), "w") do io
  40.             serialize(io, Dict("mean" => μ, "std" => σ))
  41.         end
  42.     end
复制代码
2、创建模子
  1. struct MyModel
  2.         proj_in
  3.         proj_out
  4.         pos_enc_src
  5.         pos_enc_tgt
  6.         encoder
  7.         decoder
  8.     end
  9.     Flux.@layer MyModel  # 让 Flux 知道如何提取参数
  10.     function (m::MyModel)(x)
  11.         src, tgt = x
  12.         batch = size(src, 3)
  13.         src_proj = m.proj_in.(eachslice(src, dims=1)) |> (arr -> hcat(arr...)) |> (arr -> reshape(arr, size(m.proj_in.weight, 1), size(src, 1), batch))
  14.         src_proj = src_proj .+ m.pos_enc_src[:, 1:size(src,1)]
  15.         memory = m.encoder(src_proj)
  16.         tgt_proj = m.proj_in.(eachslice(tgt, dims=1)) |> (arr -> hcat(arr...)) |> (arr -> reshape(arr, size(m.proj_in.weight, 1), size(tgt,1), batch))
  17.         tgt_proj = tgt_proj .+ m.pos_enc_tgt[:, 1:size(tgt,1)]
  18.         dec_out = m.decoder(tgt_proj, memory)
  19.         output = m.proj_out.(eachslice(dec_out, dims=2)) |> (arr -> hcat(arr...)) |> (arr -> reshape(arr, size(tgt,1), size(tgt,2), batch))
  20.         return output
  21.     end
  22.     function build_model(in_len::Int, out_len::Int, feature_dim::Int;
  23.         d_model::Int=64, nhead::Int=4, num_enc::Int=2, num_dec::Int=2)
  24.         proj_in = Dense(feature_dim, d_model)
  25.         proj_out = Dense(d_model, feature_dim)
  26.         pos_enc_src = positional_encoding(d_model, in_len)
  27.         pos_enc_tgt = positional_encoding(d_model, out_len)
  28.         enc_layers = [encoder_layer(d_model, nhead) for _ in 1:num_enc]
  29.         encoder = Chain(enc_layers...)
  30.         dec_layers = [decoder_layer(d_model, nhead) for _ in 1:num_dec]
  31.         decoder = decode_chain(dec_layers)
  32.         return MyModel(proj_in, proj_out, pos_enc_src, pos_enc_tgt, encoder, decoder)
  33.     end
复制代码
# 位置编码    function positional_encoding(d_model::Int, length::Int)        # 初始化一个矩阵来存储位置编码        pe = zeros(Float64, d_model, length)        for pos in 1:length            for i in 1:d_model                if i % 2 == 1                    pe[i, pos] = sin(pos / 10000^(2 * (i - 1) / d_model))                else                    pe[i, pos] = cos(pos / 10000^(2 * (i - 1) / d_model))                end            end        end        return pe    end    # 定义单个编码器层    function encoder_layer(d_model::Int, nheads::Int, dropout=0.1)        # 自注意力层        attention = MultiHeadAttention(d_model; nheads=nheads, dropout_prob=dropout)        # 输出投影层,将各个 head 的输出组合为 d_model 维度        out_proj = Dense((d_model ÷ nheads) * nheads, d_model)        # 前馈网络        feedforward = Chain(            Dense(d_model, 4 * d_model, relu),  # 增长维度            Dense(4 * d_model, d_model)         # 恢复原维度        )        # 归一化层和残差连接        return Chain(            LayerNorm(d_model),            x -> out_proj(attention(x, x, x)[1]) .+ x,  # 残差连接            LayerNorm(d_model),            feedforward        )    end    # 定义一个解码器层    function decoder_layer(d_model::Int, nheads::Int, dropout=0.1)        # 自注意力层        self_attention = MultiHeadAttention(d_model; nheads=nheads, dropout_prob=dropout)        # 编码器-解码器注意力层        encoder_attention = MultiHeadAttention(d_model; nheads=nheads, dropout_prob=dropout)        # 输出投影层,将各个 head 的输出组合为 d_model 维度        out_proj = Dense((d_model ÷ nheads) * nheads, d_model)        # 前馈网络        feedforward = Chain(            Dense(d_model, 4 * d_model, relu),            Dense(4 * d_model, d_model)        )        norm1 = LayerNorm(d_model)        norm2 = LayerNorm(d_model)        norm3 = LayerNorm(d_model)
        return (tgt, memory) -> begin            # 自注意力残差连接            x = norm1(tgt)            # self_attention 返回一个元组,取第一个作为注意力输出            attn_out = self_attention(x, x, x)[1]            x = out_proj(attn_out) .+ tgt
            # 编码器-解码器注意力残差连接            x_norm = norm2(x)            enc_attn_out = encoder_attention(x_norm, memory, memory)[1]            x = out_proj(enc_attn_out) .+ x
            # 前馈网络残差连接            x_norm = norm3(x)            x = feedforward(x_norm) .+ x
            return x        end    end3、训练
  1. loss_fn(model, src, tgt) = Flux.Losses.mse(model((src, tgt)), tgt)
  2.     function train_model!(model, data; epochs::Int=10, batch_size::Int=32, lr::Float64=1e-3)
  3.         src_all, tgt_all = data
  4.         N = size(src_all, 3)
  5.         opt = Flux.setup(ADAM(lr), model)
  6.         for epoch in 1:epochs
  7.             epoch_loss::Float32 = 0.0
  8.             idxs = randperm(N)
  9.             for batch in partition(idxs, batch_size)
  10.                 src_batch = src_all[:, :, collect(batch)]
  11.                 tgt_batch = tgt_all[:, :, collect(batch)]
  12.                 grads = Flux.gradient(loss_fn, model, src_batch, tgt_batch)[1]
  13.                 Flux.update!(opt, model, grads)
  14.                 epoch_loss += loss_fn(model, src_batch, tgt_batch)
  15.             end
  16.             println("Loss: $(epoch_loss)")
  17.             flush(stdout)
  18.         end
  19.     end
复制代码
# ================================    # 4. 遍历多个 CSV 文件训练    # ================================
    function train_multiple_csvs(data_dir::String;epochs::Int=200)        csv_files = glob("data_*.csv", data_dir)        # 加载均值和标准差        stats = open(joinpath(Common.get_runtime_dir(), "../config/data_stats.jls"), "r") do io            deserialize(io)        end        μ = stats["mean"]        σ = stats["std"]        # 构建模子        in_len = 60        out_len = 30        feature_dim = 1534        epochs = epochs        model = build_model(in_len, out_len, feature_dim; d_model=64, nhead=4, num_enc=2, num_dec=2)        # println(Flux.params(model))        for epoch in 1:epochs            println("Epoch $epoch")            flush(stdout)            for filepath in csv_files                println("rocessing: $filepath")                flush(stdout)                df = load_csv_data(filepath)                X = preprocess_data(df, μ, σ)                src_data, tgt_data = create_windows(X, in_len, out_len)                src_data = Float32.(src_data)                tgt_data = Float32.(tgt_data)                feature_dim = size(X, 2)                            train_model!(model, (src_data, tgt_data), epochs=1, batch_size=32, lr=1e-3)               end        end            save_model(model, joinpath(Common.get_runtime_dir(), "../config/model.bson"))            end 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

汕尾海湾

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表