3

In my python script, I've created a class which, among others, contains keras models like so:

from keras.layers import Input, Activation, Dense
from keras.models import Model


class Klass:

    def __init__(self, input_dims, output_dims, hidden_dims, optimizer, a, b):

        self.input_dims = input_dims
        self.output_dims = output_dims
        self.hidden_dims = hidden_dims
        self.optimizer = optimizer
        self.a = a
        self.b = b

        self.__build_nn()

    def __build_nn(self):

        inputs = Input(shape=(self.input_dims,))
        net = inputs
        for h_dim in self.hidden_dims:
            net = Dense(h_dim, kernel_initializer='he_uniform')(net)
            net = Activation("relu")(net)

        outputs = Dense(self.output_dims)(net)
        outputs = Activation("linear")(outputs)
        self.nn1 = Model(inputs=inputs, outputs=outputs)
        self.nn2 = Model(inputs=inputs, outputs=outputs)
        self.nn1.compile(optimizer=self.optimizer, loss='mean_squared_error')
        self.nn2.compile(optimizer=self.optimizer, loss='mean_squared_error')

After creating a Klass instance, I would like to make a deep copy of it:

import copy
obj = Klass(10, 10, (20, 20), Adam(), 1, 2)
obj_dc = copy.deepcopy(obj)

However, this throws a TypeError: can't pickle _thread.RLock objects. I am pretty sure that the error is related to the keras models in the class object since I was able to get a deep copy of a similar class without the keras models.

Unfortunately, I was unable to find a solution to this on the internet, since most questions concerning deep copying a keras model were trying to clone a keras model like here.

So, how can I get a deep copy of a class containing the keras models?

EDIT

These three questions (1, 2, 3) mention a similar error under different circumstances. Yet, the solutions offered there do not apply in my case.

EDIT 2

As suggested in the comments, I've added a copy method in the class. Would that be a viable solution?

class Klass:

    def __init__(self, input_dims, output_dims, hidden_dims, optimizer, a, b):

        self.input_dims = input_dims
        self.output_dims = output_dims
        self.hidden_dims = hidden_dims
        self.optimizer = optimizer
        self.a = a
        self.b = b

        self.__build_nn()

    # [...]

    def copy(self):

        new = Klass(self.input_dims, self.output_dims, self.hidden_dims,
                    self.optimizer, self.a, self.b)
        new.nn1.set_weights(self.nn1.get_weights())
        new.nn2.set_weights(self.nn2.get_weights())

        return new
apitsch
  • 1,532
  • 14
  • 31
  • Sounds tricky since Keras does a lot of things under the hood, depending on your environment. I would write a `copy` method for `Klass`, in which I create another object of `Klass` and copy the weights over new one. Would this satisfy your needs? – Kota Mori Oct 05 '18 at 22:19
  • @KotaMori Thanks for your suggestion. Would the added `copy` method (Edit 2) be a "pythonic" way of achieving the desired result? – apitsch Oct 05 '18 at 22:39
  • Slightly better would be to use `keras.models.clone_model` but I don't think there is much difference from copying the weights. https://github.com/keras-team/keras/issues/1765. Although I don't know if this is pythonic, it seems there are not so many other options either. – Kota Mori Oct 05 '18 at 22:56

1 Answers1

0

Solved in comments: Added a copy method for Klass which copies the weights from the old Klass instance to the newly created one.

apitsch
  • 1,532
  • 14
  • 31