8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

训练 PINN 来反演未知参数

Vincent van der Weele 2月前

116 0

我正在使用 PINN 求解阻尼振荡器微分方程,并同时找到后者的摩擦参数,给定阻尼振荡器的噪声观测值作为输入。我写道...

我正在使用 PINN 来求解阻尼振荡器微分方程,同时找到后者的摩擦参数,给定阻尼振荡器的噪声观测作为输入。我使用自定义训练程序使用 Tensorflow 编写了代码。问题是我定义的可训练参数并没有接近我从噪声观测中知道的正确值。最终,PINN 的解决方案完全不正确。但是,我的代码运行良好,无需寻找可训练参数(即此处的摩擦参数)的附带任务。

以下功能解释:

  • 振荡器系统数据损失:振荡器系统作为神经网络的实现,其中可学习参数 mu 被传递给 NN_osc_func 中实现的 ODE
  • train_NN_data_loss:自定义训练程序
  • plot_epochs_with_noise:与问题无关,但用于训练时的监控
def oscillator_system_data_loss(t, net, func, params, mu, bc, t_data, u_data, lambda1):
    t = t.reshape(-1,1)
    t = tf.constant(t, dtype = tf.float32)
    t_0 = tf.zeros((1,1))

    with tf.GradientTape() as outer_tape:
        outer_tape.watch(t)
         
        with tf.GradientTape() as inner_tape:
            inner_tape.watch(t)
            x = net(t)
     
        dx_dt = inner_tape.gradient(x, t)  # 1st derivative
 
    d2x_dt2 = outer_tape.gradient(dx_dt, t)  # 2nd derivative
    
    bc_loss_1 = tf.square(net(t_0) - bc[0])
    bc_loss_2 = tf.square(dx_dt[0] - bc[1])
        
    ode_loss = d2x_dt2 - func(x, dx_dt, params[0], mu, params[2])
    
    data_loss = u_data - net(t_data)

    square_loss = tf.square(ode_loss) + lambda1*tf.square(data_loss) + bc_loss_1 + bc_loss_2
    total_loss = tf.reduce_mean(square_loss)

    return total_loss, mu

def train_NN_data_loss(epochs, optm, NN, func, bc, lambda1, train_t, train_u, data_t, data_u,
                       data_u_noised, test_t_plot, true_u_plot, testing_t):
    train_loss_record = []
    loss_tracker = plotting_points(epochs)
    
    mu = tf.Variable(initial_value=tf.ones((1,1)), trainable=True, dtype=tf.float32)
    mu_list = []
    
    early_stop = 0
    
    for itr in range(epochs):
        with tf.GradientTape() as tape:
            train_loss, mu = oscillator_system_data_loss(train_t, NN, func, params, mu, bc, data_t, data_u_noised, lambda1)
            train_loss_record.append(train_loss)
            
            grad_w = tape.gradient(train_loss, NN.trainable_variables + [mu])
            optm.apply_gradients(zip(grad_w, NN.trainable_variables + [mu]))
    
        if itr in loss_tracker:
            print(train_loss.numpy())
            print(mu.numpy())
            plot_epochs_with_noise(train_t, train_u, data_t, data_u_noised, test_t_plot, true_u_plot, testing_t, itr, NN)
    
        mu_list.append(mu.numpy()) 
            
    return train_loss_record, mu_list, early_stop

NN_osc_func = lambda x, dx_dt, k, d, m: -k/m*x - d/m*dx_dt

您可以在此处看到 6000 个 epoch 后的结果。神经网络收敛到一条水平线,误差为 5.76,参数估计为 0.84,尽管正确值为 4。这是我的阻尼振荡器设置:

k = 400
d = 4
m = 1
y0 = np.array([1.0, 0.0])

错误的结果。

相应损失。

不幸的是,目前我不知道问题可能出在哪里。我尝试更改 NN_osc_func 在这两个函数中 tape.gradient() 尝试了

我的一些想法是,要么训练更长时间,要么我可能会遇到 PINN 容易出现的一些高频问题。

帖子版权声明 1、本帖标题:训练 PINN 来反演未知参数
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Vincent van der Weele在本站《tensorflow》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 我正在尝试访问可以在急切模式或图形模式下运行的函数内的 python 列表,如下所示:import tensorflow as tfimport numpy as npclass SlotGenerator: def __init__(self...

    我正在尝试访问可以在急切模式或图形模式下运行的函数内的 python 列表,如下所示:

    import tensorflow as tf
    import numpy as np
    
    class SlotGenerator:
      def __init__(self):
        pass  # No need for initialization here
    
      def call(self):
          real_part = tf.random.uniform((1, 1, 30720), dtype=tf.float32)
          imag_part = tf.random.uniform((1, 1, 30720), dtype=tf.float32)
          return tf.complex(real_part, imag_part)
    
    class WaveformGenerator:
      def __init__(self, slot_numbers):
        self.slotgens = [SlotGenerator() for _ in range(len(slot_numbers))]
        
      def gen_single_slot(self, slot_num):
        # Generate random slot_matrix with desired dimensions
        return self.slotgens[slot_num].call()
      
      def gen_slots(self, slot_numbers, batch_size=1, num_ant=1, num_time_samples=30720):
          """Generate slots specified by slot_nos"""
            
          slot_shape = tf.TensorShape([batch_size, num_ant, num_time_samples])
    
          slots = tf.map_fn(
                lambda slot_num: self.gen_single_slot(slot_num),
                slot_numbers,
                fn_output_signature=tf.TensorSpec(shape=slot_shape, dtype=tf.complex64)
            )
            
          slots = tf.squeeze(slots, axis=[1]) # tf.map_fn adds an extra dimension at the beginning of the tensor
          return tf.concat(slots, axis=0)
    
      def __call__(self, slot_numbers, eager_mode=False):
    
        if not eager_mode:
            self.gen_slots = tf.function(self.gen_slots)
        
        slots = self.gen_slots(slot_numbers)
    
        return slots
    
    # Example usage
    
    slot_numbers = [0,1,2,3,4]  # Example number of slots
    slot_numbers = np.array(slot_numbers, dtype=np.int32)
    waveform_generator = WaveformGenerator(slot_numbers)
    
    eager_mode = False   
    waveform = waveform_generator(slot_numbers, eager_mode=eager_mode)
    
    print(waveform.shape)  # Expected output shape: ([5, 1, 30720])
    

    这在 Eager 模式(设置 eager_mode = True)下运行良好,但在图形模式(设置 eager_mode = False)下失败,并出现以下错误:

    TypeError:列表索引必须是整数或切片,而不是 SymbolicTensor

    在图形模式下,是否有解决此列表索引问题的方法?或者图形模式是否支持除 Python 列表之外的其他类型,我可以在其中存储类对象?

  • 我需要遍历 json 对象并找到大小与给定值匹配的键对象、键数组。我不明白在哪里设置条件。函数遍历(obj,size){for(let...

    我需要遍历 json 对象并找到大小与给定值匹配的键对象和键数组。

    我不明白在哪里设置条件。

    function traverse(obj, size) {
        for (let key in obj) {
            if (typeof obj[key] === "object" && obj[key] != null) {
                traverse(obj[key]);
                if (Object.keys(obj[key]).length > size) {
                    console.log(key);
                } else if (Array.isArray(obj[key])) {
                    if (obj[key].length > size) { 
                        console.log(key);
                    }
                } 
            }
        }
    }
    

    我尝试重新排列 if 条件,但没有得到任何好的结果

    样本测试对象

    let objTest = {
        "id": "66100c8e58d0a40e97ce7753",
        "createdBy": "crm1",
        "attributes": {
            "accountsInfoMessages": [{
                "valueOzb": "Mijozning holati yoritilgan. Hisob yaratish mumkin emas. Mijoz ma'lumotlarini to'ldiring. Buning uchun \"Kartochkani tanrirlash\" tugmasini bosing.",
                "code": "notCreateAccount",
            }, {
                "valueOzb": "Mijozning holati yoritilgan. Hisob yaratish mumkin emas. Mijoz ma'lumotlarini to'ldiring. Buning uchun \"Kartochkani tanrirlash\" tugmasini bosing.",
                "code": "notCreateAccount",
            }, {
                "valueOzb": "Mijozning holati yoritilgan. Hisob yaratish mumkin emas. Mijoz ma'lumotlarini to'ldiring. Buning uchun \"Kartochkani tanrirlash\" tugmasini bosing.",
                "code": "notCreateAccount",
            }],
            "selectedCardProduct": null,
            "homePageId": null,
            "branch": null,
            "customerId": "1111",
            "selectForCurrencyTest": "111",
            "selectForFiltersCardType": {
                "values": [{
                    "code": "01",
                    "valueOzb": "HUMO"
                }, {
                    "code": "02",
                    "valueOzb": "UzCard",
                }, {
                    "code": "03",
                    "valueOzb": "Visa"
                }],
            },
            "selectForCurrency": [{
                "valueOzb": "Andor pesetasi",
                "code": "ADP"
            }, {
                "code": "AED",
                "valueOzb": "Birlashgan Arab Amirliklari dirhami"
            }, {
                "valueOzb": "Afg'ani",
                "code": "AFA"
            }, ]
        },
        "selectForCurrency": "Test"
    }
    
  • 我根据自己的理解修正了函数的某些部分。这应该可以正常工作。如果不行,请在评论中告诉我您遇到了什么错误/漏洞。最好在您的问题中添加您正在遍历的对象的实例/简化示例。

    编辑:这是经过测试的解决方案的最终草案:

    /* Test Data: */
    const testObject = {
      owner: 'John Doe',
      prices: [200, 450, -400, 3000, -650, -130, 70, 1300],
      interestRate: 1.2, // %
      pin: 1111,
      nullVal: null,
      objOuter: {
        one: 1,
        two: 2,
        three: 3,
        arr1: [200, 450, -650],
        inner: {
          uno: 1,
          dos: 2,
          tres: 3,
          arr2: [-400, 3000],
          innermost: {
            ich: 1,
            ni: 2,
            san: 3,
            arr3: [-130, 70, 1300],
          },
        },
      },
    };
    
    /* Function: */
    function traverse(obj, size) {
      for (const [key, val] of Object.entries(obj)) {
        if (!val) continue;
        if (Array.isArray(val) && val.length > size) {
          console.log(key);
          val.forEach(function (el, i) {
            if (typeof el === 'object') traverse(el, size);
          });
        }
        if (typeof val === 'object' && !Array.isArray(val) && Object.keys(val).length > size) {
          console.log(key);
          traverse(val, size);
        }
      }
    }
    traverse(testObject, 3); // Function call
  • 谢谢。看起来它正在工作。问题仅在于当值是 null 时,在检查数组时 - Object.keys(val) 无法转换 null。我添加了一个检查 null 的语句 if (typeof val === 'object' && val != null && !Array.isArray(val) && Object.keys(val).length > size)

  • 您不需要检查“null”值,因为条件 (typeof val === \'object\') 会处理它。如果 val 是对象类型,即使它为空,其值也不会为 null。就像 console.log({}); 和 console.log([]); 不会打印 null 一样。如果 val 是空对象/数组,则检查其大小/长度的条件将为 false,并且 val 将被忽略。

  • 如果不进行检查,它会在 Object.keys(val) 上抛出“TypeError:无法将未定义或 null 转换为对象”。我已附加一个示例对象。

  • 是的。似乎就是这样。为了正确修复它,我建议在函数的 for-of 循​​环顶部添加此行:if (!val) continue;。我在对答案的最后编辑中添加了此行。

  • 您仅使用一个参数调用 traverse。

    if (typeof obj[key] === "object" && obj[key] != null) {
        traverse(obj[key]); // here !
         //... rest of the code
    }
    
    

    它应该是

    traverse(obj[key], size);
    

    请提供具有所需结果的对象示例以验证逻辑

  • 引用 10

    您好,我使用 keras 训练了一个 CNN 模型,该模型类似于他们在网站上使用的示例模型,但层数略小,并且在末尾有一个额外的 dropout 层。模型构建函数看起来...

    嗨,我用 keras 训练了一个 CNN 模型,类似于他们在网站上使用的示例模型,但层数略小,最后还有一个额外的 dropout 层。模型构建函数看起来有点像这样:

    " --------- Model Params ---------"
    
    epochs = 800
    image_size = (384, 256)
    batch_size = 128
    number_of_layers = 4
    drop_out = 0.25
    num_dropouts = 2
    learn_rate = 0.00001
    layer_sizes = [64, 128, 256, 512, 728]
    class_weight = {0:1, 1:3}
    image_rotation = 0.1
    
    
    def make_model(input_shape, num_classes, layer_num=3, drop_out=0.25, dropouts=1):
        inputs = keras.Input(shape=input_shape)
    
        # Entry block
        x = layers.Rescaling(1.0 / 255)(inputs)
        x = layers.Conv2D(128, 3, strides=2, padding="same")(x)
        x = layers.BatchNormalization()(x)
        x = layers.Activation("relu")(x)
    
        previous_block_activation = x  # Set aside residual
        
        layer_use = []
        for i in range(layer_num): layer_use.append(layer_sizes[i])
            
        for size in layer_use:
            x = layers.Activation("relu")(x)
            x = layers.SeparableConv2D(size, 3, padding="same")(x)
            x = layers.BatchNormalization()(x)
    
            x = layers.Activation("relu")(x)
            x = layers.SeparableConv2D(size, 3, padding="same")(x)
            x = layers.BatchNormalization()(x)
    
            x = layers.MaxPooling2D(3, strides=2, padding="same")(x)
    
            # Project residual
            residual = layers.Conv2D(size, 1, strides=2, padding="same")(
                previous_block_activation
            )
            x = layers.add([x, residual])  # Add back residual
            previous_block_activation = x  # Set aside next residual
    
        x = layers.SeparableConv2D(1024, 3, padding="same")(x)
        x = layers.BatchNormalization()(x)
        x = layers.Activation("relu")(x)
    
        x = layers.GlobalAveragePooling2D()(x)
        if num_classes == 2:
            units = 1
        else:
            units = num_classes
        
    
        if dropouts == 1:
            x = layers.Dropout(drop_out)(x)
            # We specify activation=None so as to return logits
            outputs = layers.Dense(units, activation=None)(x)
        elif dropouts == 2:
            x = layers.Dropout(0.2)(x)
            x = layers.Dense(units, activation=None)(x)
            outputs = layers.Dropout(drop_out)(x)
    
        return keras.Model(inputs, outputs)
    
    model = make_model(input_shape=image_size + (3,), num_classes=2, layer_num=number_of_layers, 
                       drop_out=drop_out, dropouts=num_dropouts)
    
    model.compile(
        optimizer=keras.optimizers.Adam(learning_rate=learn_rate),
        loss=keras.losses.BinaryCrossentropy(from_logits=True),
        metrics=[keras.metrics.BinaryAccuracy(name="acc")],
      )
    
    model.fit(
        train_ds,
        epochs=epochs,
        callbacks=callbacks,
        validation_data=val_ds,
        class_weight=class_weight
    )
    

    该模型训练良好 - 验证准确率达到 97% 左右。使用预测函数时,模型通常会根据我提供的输入数据给出合理的输出。我遇到的问题是,使用该 predict_on_batch 函数时的输出预测并不相同,如果使用相同的输入数据重复,通常会相差 +-0.15。这是什么原因造成的,一旦模型经过训练并用于预测,对于相同的输入数据,预测难道不应该相同吗?

    1. 您应该将参数传递给递归调用
    2. 您可以添加一个累加器来收集结果

    let objTest={id:"66100c8e58d0a40e97ce7753",createdBy:"crm1",attributes:{accountsInfoMessages:[{valueOzb:"Mijozning holati yoritilgan. Hisob yaratish mumkin emas. Mijoz ma'lumotlarini to'ldiring. Buning uchun \"Kartochkani tanrirlash\" tugmasini bosing.",code:"notCreateAccount"},{valueOzb:"Mijozning holati yoritilgan. Hisob yaratish mumkin emas. Mijoz ma'lumotlarini to'ldiring. Buning uchun \"Kartochkani tanrirlash\" tugmasini bosing.",code:"notCreateAccount"},{valueOzb:"Mijozning holati yoritilgan. Hisob yaratish mumkin emas. Mijoz ma'lumotlarini to'ldiring. Buning uchun \"Kartochkani tanrirlash\" tugmasini bosing.",code:"notCreateAccount"}],selectedCardProduct:null,homePageId:null,branch:null,customerId:"1111",selectForCurrencyTest:"111",selectForFiltersCardType:{values:[{code:"01",valueOzb:"HUMO"},{code:"02",valueOzb:"UzCard"},{code:"03",valueOzb:"Visa"}]},selectForCurrency:[{valueOzb:"Andor pesetasi",code:"ADP"},{code:"AED",valueOzb:"Birlashgan Arab Amirliklari dirhami"},{valueOzb:"Afg'ani",code:"AFA"},]},selectForCurrency:"Test"};
    
    function traverse(obj, size, key = null, result = []) {
      if(Array.isArray(obj)){
        obj.forEach((item,i) => traverse(item, size, i, result));
        obj.length > size && key && result.push(key);
      } else if (obj && typeof obj === "object") {
        const keys = Object.keys(obj);
        keys.forEach(key => traverse(obj[key], size, key, result));
        keys.length > size && key && result.push(key);
      }
      return result;
    }
    
    console.log(traverse(objTest, 1));
  • \'一旦模型经过训练并用于预测,对于相同的输入数据,预测结果难道不应该相同吗?\'。我认为这取决于您的代码,您使用的是自然随机的 Dropout。除此之外,可能还有其他参数需要考虑

  • 谢谢你的回复。该函数返回一个空数组。我无法调试错误在哪里。我已附加一个测试对象。

  • 此代码创建一个客户端类,其中包含变量名称、到达时间和延迟。循环通过读取客户端的到达时间、为其添加延迟并将其设为到达时间,在队列中创建新的客户端。

    此代码创建一个客户端类,其中包含变量 name , arrival time 、 和 delay 。循环通过读取客户端的到达时间、为其添加延迟以及使新客户端到达的时间成为队列中的新客户端。将客户端对象附加到队列时,所有客户端对象都是不同的,但是当我尝试读取它们时,它们仅在到达时间上变得相同。为什么会发生这种情况?

    import random
    import numpy as np
    import collections
    
    # a client class for creating a queue using a poisson distribution. The clients are added to a deque
    class Client:
        def __init__(self):
            self.name = random.choice(["Juan", "julia", "Daniel", "Rafael", "Lida", "Sandra"])
            self.arrival_time = 0
            self.arrival_time_delay = np.random.poisson(5, size=1)
    
        def __str__(self) -> str:
            return "Client: {} arrival-time: {} delay {}".format(self.name, self.arrival_time, self.arrival_time_delay)
    
    
    client_count = 5
    queue = collections.deque()
    
    # arrival
    time_added = 0
    # adding clients to a deque 
    for _ in range(client_count):
        client = Client()
        # a new time is the arrival time plus a delay for the next client to appear
        client.arrival_time = time_added
        print(client)
        queue.append(client)
        time_added += client.arrival_time_delay
    
    print(60 * "#")
    
    for c in queue:
        print(c)
    
    #results:
    #Client: julia arrival-time: 0 delay [6]
    #Client: Sandra arrival-time: [6] delay [3]
    #Client: Lida arrival-time: [9] delay [4]
    #Client: Juan arrival-time: [13] delay [8]
    #Client: Sandra arrival-time: [21] delay [6]
    ############################################################
    #Client: julia arrival-time: 0 delay [6]
    #Client: Sandra arrival-time: [27] delay [3]
    #Client: Lida arrival-time: [27] delay [4]
    #Client: Juan arrival-time: [27] delay [8]
    #Client: Sandra arrival-time: [27] delay [6]
    
返回
作者最近主题: