hunglc007 / tensorflow-yolov4-tflite

YOLOv4, YOLOv4-tiny, YOLOv3, YOLOv3-tiny Implemented in Tensorflow 2.0, Android. Convert YOLO v4 .weights tensorflow, tensorrt and tflite
https://github.com/hunglc007/tensorflow-yolov4-tflite
MIT License
2.24k stars 1.24k forks source link

transfer learning broken using weights from google drive #13

Open alexis-gruet-deel opened 4 years ago

alexis-gruet-deel commented 4 years ago

train.py with --weights=./yolov4.weights cause an assert error under utils.load_weights If assert len(wf.read()) == 0, 'failed to read all data' is commented the training start with nan

=> STEP   63   lr: 0.000027   giou_loss:  nan   conf_loss:  nan   prob_loss:  nan   total_loss:  nan
=> STEP   64   lr: 0.000028   giou_loss:  nan   conf_loss:  nan   prob_loss:  nan   total_loss:  nan
bgamini commented 4 years ago

Same problem, when trying to transfer learning with custom classes (number of classes should be 80).

bgamini commented 4 years ago

I solved the problem by using pickle, but definitely this is not the correct way :)

weights_to_pickle.py:

from core.yolov4 import YOLOv4, decode
import tensorflow as tf
import core.utils as utils
import pickle

input_layer = tf.keras.layers.Input([608, 608, 3])
feature_maps = YOLOv4(input_layer, NUM_CLASS=80)
model = tf.keras.Model(input_layer, feature_maps)
utils.load_weights(model, "./data/yolov4.weights")
weights = []
for layer in model.layers:
    weights.append(layer.get_weights())
pickle.dump(weights, open("./data/yolov4.pkl", 'wb'))

and adding this to train.py file after line 78:

elif FLAGS.weights.split(".")[len(FLAGS.weights.split(".")) - 1] == "pkl":
    weights = pickle.load(open(FLAGS.weights, 'rb'))
    num_loaded_layers = 0
    for i, w in enumerate(weights):
        try:
            model.layers[i].set_weights(w)
        except:
            num_loaded_layers = i
            break
    print("=========", num_loaded_layers ,"layers loaded successfully ==========")

Note: you can use model.layers[i].trainable = False

hunglc007 commented 4 years ago

In config.py, did you change __C.YOLO.CLASSES == your .names file ?

alexis-gruet-deel commented 4 years ago

@hunglc007 : Yes, I confirm.

hunglc007 commented 4 years ago

Your .weights file is trained by darknet with your custom data ? Did you use yolov4.cfg or your custom .cfg file ?

alexis-gruet-deel commented 4 years ago

@hunglc007 : "Your .weights file is trained by darknet with your custom data ?" No, the weights file i used (and @bgamini ) is the one attached on the readme.md of this repository.

Consequently, as your 2nd question "Did you use yolov4.cfg or your custom .cfg file ?" No, this does not apply.

jzoker commented 4 years ago

@MI-LA01 do you pull the lastest code ? i just 've ran main.py with --weights=./yolov4.weights and there was no problem.

alexis-gruet-deel commented 4 years ago

@jzoker : Yes, I confirmed to pulled from master yesterday, and downloaded the weights mean time.

wsypy commented 4 years ago

In config.py, did you change __C.YOLO.CLASSES == your .names file ?

When we modify the coco.names, in _ C.YOLO.classes =\ ". / data/classes/coco.names\" in the config.py file, change it to mywork.names. If we use yolov4.weights again, we will make mistakes, whether in detect.py or train.py. Because the number of objects in coco.names is not the same as that in mywork.names.

wsypy commented 4 years ago

I solved the problem by using pickle, but definitely this is not the correct way :)

weights_to_pickle.py:

from core.yolov4 import YOLOv4, decode
import tensorflow as tf
import core.utils as utils
import pickle

input_layer = tf.keras.layers.Input([608, 608, 3])
feature_maps = YOLOv4(input_layer, NUM_CLASS=80)
model = tf.keras.Model(input_layer, feature_maps)
utils.load_weights(model, "./data/yolov4.weights")
weights = []
for layer in model.layers:
    weights.append(layer.get_weights())
pickle.dump(weights, open("./data/yolov4.pkl", 'wb'))

and adding this to train.py file after line 78:

elif FLAGS.weights.split(".")[len(FLAGS.weights.split(".")) - 1] == "pkl":
    weights = pickle.load(open(FLAGS.weights, 'rb'))
    num_loaded_layers = 0
    for i, w in enumerate(weights):
        try:
            model.layers[i].set_weights(w)
        except:
            num_loaded_layers = i
            break
    print("=========", num_loaded_layers ,"layers loaded successfully ==========")

Note: you can use model.layers[i].trainable = False

Thank you for 'pickle' method. Now I can use the VOC dataset for training. Although I don't know if it's normal to train in this way.

Note: youcanusemodel.layers [I] .trainable = False Does this code mean that the pre-training weight doesn't work?

Model. Layers [I]. Set _ weights (w) When I use this line of code does it mean that I use pre-training weights?

It is hoped that this code base can be further improved. It is also easy to train when we use a dataset with a class number other than 80.

Thank you to the author and everyone!

ShihuaiXu commented 4 years ago

@hunglc007 Please fix this problem, I want to train my custom data with transfer learning, thank you very much

hunglc007 commented 4 years ago

I updated mish activation to fix nan loss issue.