stared / livelossplot

Live training loss plot in Jupyter Notebook for Keras, PyTorch and others
https://p.migdal.pl/livelossplot
MIT License
1.29k stars 142 forks source link

PlotLossesKeras not working due to TypeError #3

Closed fculinovic closed 6 years ago

fculinovic commented 6 years ago

For Keras version 2.1.3 the PlotLossesKeras crashes due to error in line 33 of keras_plot.py

Reason for this is: self.metric2printable['loss'] = self.metric2printable.get(self.model.loss, self.model.loss) + " (cost function)" where this breaks due to self.model.loss being a keras function. This results in

TypeError: unsupported operand type(s) for +: 'function' and 'str'

stared commented 6 years ago

With Keras 2.0.5 it works well.

In any case - how did you specify the loss function? (Could you provide code, at least model.compile and model.fit lines?)

fculinovic commented 6 years ago

Model is compiled with

model.compile(loss=keras.losses.binary_crossentropy,
              optimizer=keras.optimizers.Adam(lr=1e-3, amsgrad=True),
             metrics=['accuracy'])

Fitting is done according to your example:

model.fit(data[m_train], labels[m_train],
    epochs=10, verbose=True,
    validation_data=(data[m_val], labels[m_val]),
    callbacks=[checkpointer, PlotLossesKeras()]
)

where your example does

from livelossplot import PlotLossesKeras

model.fit(X_train, Y_train,
          epochs=10,
          validation_data=(X_test, Y_test),
          callbacks=[PlotLossesKeras()],
          verbose=0)

Printing out model.loss shows that the return value of that call is the function itself <function binary_crossentropy at 0x7fa918886598>

The stacktrace is:

TypeError                                 Traceback (most recent call last)
<ipython-input-99-baaad69844e3> in <module>()
      2     epochs=10, verbose=True,
      3     validation_data=(data[m_val], labels[m_val]),
----> 4     callbacks=[PlotLossesKeras()]
      5 )

~/.local/lib/python3.5/site-packages/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, **kwargs)
   1667                               initial_epoch=initial_epoch,
   1668                               steps_per_epoch=steps_per_epoch,
-> 1669                               validation_steps=validation_steps)
   1670 
   1671     def evaluate(self, x=None, y=None,

~/.local/lib/python3.5/site-packages/keras/engine/training.py in _fit_loop(self, f, ins, out_labels, batch_size, epochs, verbose, callbacks, val_f, val_ins, shuffle, callback_metrics, initial_epoch, steps_per_epoch, validation_steps)
   1136             'metrics': callback_metrics or [],
   1137         })
-> 1138         callbacks.on_train_begin()
   1139         callback_model.stop_training = False
   1140         for cbk in callbacks:

~/.local/lib/python3.5/site-packages/keras/callbacks.py in on_train_begin(self, logs)
    127         logs = logs or {}
    128         for callback in self.callbacks:
--> 129             callback.on_train_begin(logs)
    130 
    131     def on_train_end(self, logs=None):

~/.local/lib/python3.5/site-packages/livelossplot/keras_plot.py in on_train_begin(self, logs)
     31                 ((len(self.base_metrics) + 1) // self.max_cols + 1) * self.cell_size[1]
     32             )
---> 33         self.metric2printable['loss'] = self.metric2printable.get(self.model.loss, self.model.loss) + " (cost function)"
     34         self.max_epoch = self.params['epochs'] if not self.dynamic_x_axis else None
     35 

TypeError: unsupported operand type(s) for +: 'function' and 'str'
utausheva commented 6 years ago

Got the same error

stared commented 6 years ago

Solved with this commit: https://github.com/stared/livelossplot/commit/a9734f2488d10e568fbf12bc35e39396d782db9e

Let me know if it works.

utausheva commented 6 years ago

Nothing changed((

fculinovic commented 6 years ago

This fixed the issue at my end. You sure you have used pip3 install git+git://github.com/stared/livelossplot.git@a9734f2488d10e568fbf12bc35e39396d782db9e --user ?

Here's the ending of this command

Installing collected packages: livelossplot
  Found existing installation: livelossplot 0.1.1
    Uninstalling livelossplot-0.1.1:
      Successfully uninstalled livelossplot-0.1.1
  Running setup.py install for livelossplot ... done
Successfully installed livelossplot-0.1.2
utausheva commented 6 years ago

I do. Error changed: now its: Traceback (most recent call last): File "C:/Users/ASUS/PycharmProjects/achimovka/train.py", line 108, in shuffle=True) File "C:\Users\ASUS\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\models.py", line 963, in fit validation_steps=validation_steps) File "C:\Users\ASUS\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\engine\training.py", line 1705, in fit validation_steps=validation_steps) File "C:\Users\ASUS\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\engine\training.py", line 1163, in _fit_loop callbacks.on_train_begin() File "C:\Users\ASUS\AppData\Local\Programs\Python\Python36\lib\site-packages\keras\callbacks.py", line 130, in on_train_begin callback.on_train_begin(logs) File "C:\Users\ASUS\AppData\Local\Programs\Python\Python36\lib\site-packages\livelossplot\keras_plot.py", line 42, in on_train_begin self.metric2printable['loss'] = self.metric2printable.get(loss_name, loss_name) + " (cost function)" TypeError: unhashable type: 'list'

fculinovic commented 6 years ago

Could you provide the parts of code regarding the compile and fit functions?

utausheva commented 6 years ago

model.compile(optimizer=opt, loss=['mae'], metrics=['mae']) plot_losses = livelossplot.PlotLossesKeras()

history = model.fit(X_train, Y_train, nb_epoch=10, batch_size=2, verbose=0, validation_data=(X_test, Y_test), callbacks=[reduce_lr,checkpointer,plot_losses], shuffle=True)

fculinovic commented 6 years ago

Ok, so it seems that this is the case:

if the loss is defined as model.compile(..., loss= 'mae', ...) or model.compile(..., loss=keras.losses.mean_absolute_error) it should work.

This is a solution if you have only 1 loss function. As for more loss functions, it seems that self.metric2printable['loss'] = self.metric2printable.get(loss_name, loss_name) + " (cost function)"

and the accompanying function

def loss2name(loss):
    if hasattr(loss, '__call__'):
        # if passed as a function
        return loss.__name__
    else:
        # if passed as a string
        return loss

aren't written to accomodate multiple losses

stared commented 6 years ago

@utausheva Write model.compile(optimizer=opt, loss='mae', metrics=['mae']) and it will be all right (and actually in your case metrics is not needed as we keep tract of 'mae' anyway).

For typical networks there is only one loss function, see https://keras.io/models/model/#compile. I need to dive into model.compile to make sure I pre-process data in the same way.

stared commented 6 years ago

@utausheva Please open a separate issue with PyCharm. Make sure to provide complete examples and versions. (In this thread I am deleting off-topic comments.)

stared commented 6 years ago

Looked at https://github.com/keras-team/keras/blob/master/keras/engine/training.py.

Now loss can be a list or a dict, see: https://github.com/stared/livelossplot/commit/8abe5f4e63b1a6f5a101dcae0eaf0c29747a1322.