关于可微分模拟magic fountain代码的一些问题

,

@mzhang
最近在太极官网上,看了Dr zhang写的一篇关于使用可微分sph模型实现训练魔法喷泉的博客
觉得使用一个NN近似的控制器来控制喷泉击中物体很有趣,然后又看了在github上公开的代码。但是代码中有几处的写法我不是很理解,希望Dr zhang能够多多指教。先谢谢了。

  1. 首先,在博客中提到的NN输入层的次元数是(n_models, batch_size, n_steps, n_input) (in this case, the input layer handles four dimensions: (n_models, batch_size, n_steps, n_input)). 但是在实际代码中定义的输入层的次元却是(n_models, n_steps, batch_size, n_input) (line 167). 可以看到n_stepsbatch_size位置调换了,这是一个手误还是故意这么安排的?我觉得batch_size在前的话貌似更好理解一些。

  2. 在全连接层的权重与偏置运算中(line 105-113),定义outpot这个field的意思是什么?如果只是单纯的线性运算的话,那么hidden层和output层的次元应该是相同的不是吗?如果按照初始化NN的设置(line 159-160),hidden层与output层的次元不同,那么如果在debug模式下,line 110是会报溢出的错误的。非debug模式下是可以运行的,但是这样的话忽略了hidden层溢出的部分,这样做没问题吗?

  3. 与2同样的问题,如line 249所示,target_centers是一个VectorField,次元为(BATCH_SIZE, 3)。但是在line 553处从训练数据中读取target_centers时,在debug模式下当迭代到第二个batch时target_centers会溢出。同样的问题,也在之后的fill_input_states函数中出现。

  4. 在line 211中定义test_data,但是并没有使用它。如果要使用test_data来验证训练模型模型的话该怎么考虑呢?

虽然太极在非debug模式下是可以溢出访问field的,但是这样超过事先定义好的field的次元的话是没问题的吗?或者说会有什么隐藏问题。以上,主要是关于NN定义与训练的部分,个人对于太极的使用还不是很熟练,还请多多赐教。关于模拟的部分,由于我之间没有接触过sph模型,现在还在学习当中。

Hi @C.Ying , 欢迎来到taichi社区。
感谢关注到这篇博客,关于其中的问题:

  1. 这个是确实是博客里写的内容和代码实现上有一些出入,把batch_size提前的话也没有问题
  2. 这个output 是因为从hidden出来后可能会过一个非线性激活函数,这里确实应该是把hiddenoutput的大小定义一致的,good catch。
  3. 关于越界的问题,在非debug模式下,对于超出定义维度的index,会被做一个对数组长度的取模操作,但不推荐借用这个特性,还是推荐用debug模式验证是否越界。
  4. 这里的test data是相对于training data来说的unseen data,用来验证模型的训练效果的

谢谢Dr zhang的及时回复。我大体上明白了这四点问题。

另外,如果按照源代码中设置的默认参数来训练NN控制器,其控制效果和博客中展示的有很大出入。
如下图所示,上边用的是github上公开的pretrained模型,下边是使用默认参数训练出来的模型。

可以看到使用默认参数训练出来的模型效果不好。因此,我想问的是pretrained模型在怎么训练出来的呢?是否有哪些tricks可以分享一下?(比如,batch size,train data number,weight/bias shape and learning rate etc.)
再次感谢。

pretrained
(pretrained)

continued

ours
(trained on default parameters)

06/20 追记 @mzhang

在1.2.0版本之后,taichi增加了break auto-diff rule validation 功能。
如果开启这个检查之后,现在版本的diff-sph代码将会报错。
具体是在482-483行和486-487行:

        for j in ti.static(range(3)):
            if F_pos[bs, t, i][j] < boundary_box[0][j]:
                F_pos[bs, t, i][j] = boundary_box[0][j]
                collision_normal[j] += -1.0
        for j in ti.static(range(3)):
            if F_pos[bs, t, i][j] > boundary_box[1][j]:
                F_pos[bs, t, i][j] = boundary_box[1][j]
                collision_normal[j] += 1.0

这里的两个判断语句需要先读取F_pos[bs, t, i][j]的值,再写入到F_pos[bs, t, i][j]
这违反了taichi中的auto-diff的规则(不能先读取再写入)。从而使得求出的grad是不正确的。(如果打印 weight.grad/bias.grad,会发现grad的量级在10^2~10^3。)
因此,如上面的问题一样,pretrained.pkl模型是怎么训练出来的?diff-sph有发布新的版本吗?