3

我尝试 使用 mxnet.jl 和 Flux 包将来自https://machinelearningmastery.com/cnn-models-for-human-activity-recognition-time-series-classification的 Conv1d Python Keras 示例翻译成 Julia。

我能够训练模型,但与 Keras 版本相比结果很差。我不确定我做错了什么。我认为输入形状或模型有问题。我有点困惑如何使用 mx.ArrayDataProvider。如您所见,20 个 epoch 后的准确度仅为 ~20%,而不是使用 Keras 时的 ~90%。我尝试了不同的输入形状,但没有成功:(

数据集可从以下网址下载: https ://archive.ics.uci.edu/ml/machine-learning-databases/00240/UCI%20HAR%20Dataset.zip

加载数据集的函数:

using DelimitedFiles


path_dataset = "/Users/bjoern/code/tests/HARDataset"

# load a single file as a numpy array
function load_file(file_path)
    dat = readdlm(file_path)
    return dat
end


# load a list of files and return as a 3d numpy array
function load_group(filenames, path2csv)
    loaded = []
    for name in filenames
        data = load_file(path2csv * name)
        push!(loaded, data)
    end
    # stack group so that features are the 3rd dimension
    loaded = cat(loaded...; dims=3)
    return loaded
end



# load a dataset group, such as train or test
function load_dataset_group(group, path_dataset)
    filepath = joinpath(path_dataset, group, "Inertial_Signals/")
    # load all 9 files as a single array
    filenames = []
    # total acceleration
    push!(filenames, "total_acc_x_" * group * ".txt", "total_acc_y_" * group * ".txt", "total_acc_z_" * group * ".txt")
    # body acceleration
    push!(filenames, "body_acc_x_" * group * ".txt", "body_acc_y_" * group * ".txt", "body_acc_z_" * group * ".txt")
    # body gyroscope
    push!(filenames, "body_gyro_x_" * group * ".txt", "body_gyro_y_" * group * ".txt", "body_gyro_z_" * group * ".txt")
    # load input data
    X = load_group(filenames, filepath)
    # load class output
    y = load_file(path_dataset * "/" * group * "/y_" * group * ".txt")
    return X, y
end



# load the dataset, returns train and test X and y elements
function load_dataset(path_dataset)
    # load all train
    trainX, trainy = load_dataset_group("train", path_dataset)
    println(size(trainX), size(trainy))
    # load all test
    testX, testy = load_dataset_group("test", path_dataset)
    println(size(testX), size(testy))
    println(size(trainX), size(trainy), size(testX), size(testy))
    return trainX, trainy, testX, testy
end

MXNet 版本:

using MXNet


# load data
trainX, trainy, testX, testy = load_dataset(path_dataset)

trainX_ = permutedims(trainX, (2,3,1))
testX_ = permutedims(testX, (2,3,1))

trainy_ = reshape(trainy,(7352,))
testy_ = reshape(testy, (2947,))

train_data_provider = mx.ArrayDataProvider(:data => trainX_, :label => trainy_, batch_size=32, shuffle=true)
validation_data_provider = mx.ArrayDataProvider(:data => testX_, :label => testy_,batch_size=32)


arch = @mx.chain mx.Variable(:data) =>
        #mx.Embedding(2,1) =>
        mx.Convolution(kernel=(3,), num_filter=64) =>
        mx.Activation(act_type=:relu) =>
        mx.Convolution(kernel=(3,), num_filter=64) =>
        mx.Activation(act_type=:relu) =>
        mx.Dropout(p=0.5) =>
        mx.Pooling(pool_type=:max, kernel=(2,)) =>
        mx.Flatten() =>
        mx.FullyConnected(num_hidden=100) =>
        mx.Activation(act_type=:relu) =>
        mx.FullyConnected(num_hidden=6) =>
        mx.SoftmaxOutput(mx.Variable(:label))

nnet = mx.FeedForward(arch, context = mx.cpu())
mx.fit(nnet, mx.ADAM(), train_data_provider, eval_data = validation_data_provider, n_epoch = 20, callbacks = [mx.speedometer()]);


 Info: Start training on Context[CPU0]
[ Info: Initializing parameters...
[ Info: Creating KVStore...
[ Info: TempSpace: Total 0 MB allocated on CPU0
[ Info: Start training...
[ Info: Speed: 1303.57 samples/sec
[ Info: Speed: 1364.40 samples/sec
[ Info: Speed: 1282.10 samples/sec
[ Info: Speed: 1306.47 samples/sec
[ Info: == Epoch 001/050 ==========
[ Info: ## Training summary
[ Info:           accuracy = 0.2117
[ Info:               time = 5.6121 seconds
[ Info: ## Validation summary
[ Info:           accuracy = 0.0413
[ Info: Speed: 1378.38 samples/sec
[ Info: Speed: 1350.01 samples/sec
[ Info: Speed: 1353.40 samples/sec
[ Info: Speed: 1368.58 samples/sec
[ Info: == Epoch 002/050 ==========
[ Info: ## Training summary
[ Info:           accuracy = 0.1776
[ Info:               time = 5.3959 seconds
[ Info: ## Validation summary
[ Info:           accuracy = 0.2530
[ Info: Speed: 1341.65 samples/sec
[ Info: Speed: 1366.51 samples/sec
[ Info: Speed: 1254.77 samples/sec
[ Info: Speed: 1205.79 samples/sec
.
.
.
[ Info: == Epoch 019/050 ==========
[ Info: ## Training summary
[ Info:           accuracy = 0.1822
[ Info:               time = 6.5816 seconds
[ Info: ## Validation summary
[ Info:           accuracy = 0.1411
[ Info: Speed: 1195.42 samples/sec
[ Info: Speed: 1235.22 samples/sec
[ Info: Speed: 1226.30 samples/sec
[ Info: Speed: 1240.68 samples/sec
[ Info: == Epoch 020/050 ==========
[ Info: ## Training summary
[ Info:           accuracy = 0.1792
[ Info:               time = 6.0004 seconds
[ Info: ## Validation summary
[ Info:           accuracy = 0.1788
[ Info: Speed: 1338.49 samples/sec

更新:在 Flux.jl 中也尝试过几乎相同的精度,所以我认为输入形状有问题。如何在 Flux 或 MXNet 中为 1d Conv 层安排时间序列输入数据?

添加通量版本:

using Flux, Flux.Data.MNIST, Statistics
using Flux: onehotbatch, onecold, crossentropy, throttle, relu, softmax, cpu, ADAM
using Base.Iterators: repeated, partition
using Printf

# load data
trainX, trainy, testX, testy = load_dataset(path_dataset)

# Not sure how to arrange
permutedims!(trainX, (3,2,1))
trainX = permutedims(reshape(trainX,(size(trainX,1)*size(trainX_,2),size(trainX,3))),(2,1))
permutedims!(testX, (3,2,1))
testX = permutedims(reshape(testX, (size(testX,1)*size(testX,2),size(testX,3))),(2,1))

y_train = trainy .- 1
y_test = testy .- 1

function make_minibatch(X, Y, idxs)
    X_batch = Array{Float32}(undef, 1152..., 1, length(idxs))
    for i in 1:length(idxs)
        X_batch[:, :, i] = Float32.(X[i,:])
    end
    Y_batch = onehotbatch(Y[idxs], 0:5)
    return (X_batch, Y_batch)
end

batch_size = 32
mb_idxs = partition(1:7352, batch_size)
train_set = [make_minibatch(trainX, y_train, i) for i in mb_idxs]

test_set = make_minibatch(testX, y_test, 1:2947)


model = Chain(
    Conv((3,), 1=>64, relu),
    Conv((3,), 64=>64, relu),
    Dropout(0.5),
    x -> maxpool(x, (2,)),
    x -> reshape(x, :, size(x, 3)),
    Dense(36736, 6),
    softmax,
)

train_set = Flux.cpu.(train_set)
test_set = Flux.cpu.(test_set)
model = Flux.cpu(model)

function loss(x, y)
    x_aug = x .+ 0.1f0*Flux.cpu(randn(eltype(x), size(x)))
    y_hat = model(x_aug)
    return crossentropy(y_hat, y)
end

accuracy(x, y) = mean(onecold(model(x)) .== onecold(y))

opt = Flux.ADAM()

@info("Beginning training loop...")
best_acc = 0.0
last_improvement = 0
for epoch_idx in 1:10
    global best_acc, last_improvement
    Flux.train!(loss, params(model), train_set, opt)

    acc = accuracy(test_set...)
    @info(@sprintf("[%d]: Test accuracy: %.4f", epoch_idx, acc))

end

OUTPUT:
[ Info: Beginning training loop...
[ Info: [1]: Test accuracy: 0.1775
[ Info: [2]: Test accuracy: 0.1802
[ Info: [3]: Test accuracy: 0.1843
[ Info: [4]: Test accuracy: 0.1856

有什么建议吗?提前致谢!

4

0 回答 0