이번에는 텐서플로우를 이용한 object detection에서 나만의 이미지를 사용해서 학습해보자
이번장에서도 저번장과 마찬가지로 텐서플로우 1.14 버젼으로 tf-slim패키지를 사용할 것이다.
우선 필요한 것은 찍어놓은 사진이나 찍을 카메라
그리고 라벨링할 프로그램이 필요한데.
qt 파이썬을 사용한 무료 오픈 소스인 labelimg를 사용할 것이다.
사진 설명을 입력하세요.
저번 장에서 깔았던 패키지는 기본으로
qt / libxml2 / pyqt / lxml / pandas /pillow/ matplotlib 의 설치가 필요하다.
conda install qt
conda install libxml2
conda install pyqt
conda install lxml
conda install pandas
conda install pillow
conda install matplotlib
저번 장에서 텐서플로우 테스트까지 이미 맞추셨으니 labelimg만 사용하면 되니.
다운받은 labellmg 폴더로 터미널로 이동후 터미널에서
아래와 같이 명령어 치면 만들어 진다
$ make qt5py3
그 다음 labellmg.py 실행시키면 이제 qt로 된 라벨링 프로그램이 뜰것인데 이제 이걸로 이미지를 크롭해서 학습을 진행할 것이다.
$ python labellmg.py
open으로 이미지 찍어놓은 폴더를 선택해서 이미지를 불러와서 create RectBox 로 이미지를 네모로 선택한다음
아래 사진처럼 라벨링을 하면 된다.
라벨링할때 주의할 점이 클래스 이름을 꼭 같은 클래스는 같게해야된다 만일 오타가 나거나하면 같은 이미지를 새로운 클래스로 학습되서 완전 망한다.
어쨋든 라벨링을 다하고 저장을 하게되면 그사진과 함께 그사진에 해당되는 xml파일이 생성된다 xml에는 크롭한 이미지의 크롭 위치와 클래스 이름들이 저장되어있다.
이제 라벨링 된 이미지와 xml가지고 tf-slim패키로 텐서플로우에서 학습하기 위해서 앞장에서 설명한데로 우선 이미지를 TFRecord로 변환을 해야 된다. 변환하기 위해서 그냥 있는 소스를 이용하기 위해 csv로 변환한다음 TFRecord로 변환하는데 실제 처음부터 만드시는분은 그냥 xml에서 바로 읽어서 TFRecord로 변환하시길. 번거롭고 불필요한 과정이긴 하다.
블로그는 그냥 설명을 하는거라 기존 소스로 하지만, 다 스스로 만들긴해야될 것이다.
우선 xml을 csv로 변환하는 코딩을 아래와 같이 하면된다. 코드 이름은 xml_to_csv.py로 하고
이러면 일일이 들어있는 xml파일들을 csv파일 하나로 통합시켜준다. labelimg 단점이 사진당 각각 xml파일을 만들어주므로 이걸 통합해줘야 되는데 위의 코드가 종합해서 csv로 만들어주는데 텐서플로우 에서 학습할 이미지와 테스트할 이미지를 구분해서 저장은 해놔야된다.
보통 일반적으로 하는 비율 20퍼센트 정도로 images/ 폴더 안에 train폴더 test폴더 두개를 생성해놓고 train 폴더에 80퍼센트정도 이미지와 xml파일을 test폴더에 20퍼센트 정도 이미지와 xml파일들을 위치시키고
아래 명령어로 실행시킨다.
$ python xml_to_csv.py
이제 위에서 종합한 csv파일로 텐서플로우 학습에 필요한 TFRecord 파일로 변환할 건데 코드이름을 generate_tfrecord.py로 명명한다.
그 다음 아래와 같이 코딩을 한다.
csv_input
image_dir
output_path
위 3가지의 flag값들을 잘입력해주면 텐서플로우 학습에 필요한 TFRecord파일들이 생성되게 된다.
여기서 csv파일은 images/ 폴더안에 있으니 csv_input=images/train_labels.csv 와 csv_input=images/test_labels.csv로 플래그값을 주면 되고,
이미지 경로야 image에 있으니 아래와 같이 명령어를 각각주면 train.record파일과 test.record값이 생성되게 된다.
$ python generate_tfrecord.py --csv_input=images/train_labels.csv --image_dir=images/train --output_path=train.record
$python generate_tfrecord.py --csv_input=images/test_labels.csv --image_dir=images/test --output_path=test.record
이제 텐서플로우로 학습을 시작할 건데 신경망을 처음부터 일일이 만드는건 차후 장에서 진행하도록 하고 이번 장에서는 기존에 학습된 신경망을 통해 fine-tuning 해서 진행하도록 한다.
기존에 학습된 cnn모델은 아래쪽 사이트에 가면 있으니 받으시면 된다.
모델에 대한 각각의 성능 테스트한 결과 등이 잘 정리 되어있으니 잘 받아서 테스트하면 된다. 테스트에서는 faster_rcnn_inception_v2로 진행을 할것이다 물론 faster_rcnn_incoption_resnet_v2이런게 훨 성능이 좋긴한데 느리다 테스트할때는 좋지않지만 실제 쓸려고할때는 위와같은 mAP가 좋은것들 쓰는걸 추천한다.
이제 fine-tuning할 모델을 다운 받았으면 이제 라벨링 파일을 생성한다.
이미지가 있는 루트폴더에 training이라는 폴더하나 만든다음 labelmap.pbtxt파일 생성하고 아래와 같이 만든다.
그 다음 fine-tuning하기 위해 받았던 cnn모델과 동일한 configs 파일을 수정하는데 텐서플로우 모델 다운받은곳에 research/object_detection/samles/configs 폴더에 들어가면 찾을 수 있다.
그 해당되는 cnn 모델의 config파일을 복사한다음 이미지파일이 있는곳에 training/ 폴더에 붙여넣기 한다.
그 다음 딱 3군데만 바꾸면 되는데.
1. 라벨링 갯수를 일치시킨다.
여기에 num_classes가 라벨링 갯수다 이걸 labelmap.pbtxt파일에서 만든 라벨 갯수랑 일치 시키고
기존에 텐서플로우에서 fine_tuning 하기 위해 다운받았던 .ckpt파일의 경로를 일치시켜 놓은데 109번째 줄쯤에 있다.
gradient_clipping_by_norm:10.0
fine_tune_checkpoint:"다운받은 경로/faster_rcnn_inception_v2_coco/model.ckpt"
위와 같이 바꾼다음 train데이터와 test 이미지 데이터의 경로 와 라벨링 경로를 수정해준다.
train_input_reader: {
tf_record_input_reader {
input_path: "Train 이미지의 TFRecord파일 경로"
}
label_map_path: "위에 작성했던 labelmap.pbtxt 파일 경로"
}
eval_input_reader: {
tf_record_input_reader {
input_path: "Test 이미지의 TFRecord 파일 경로"
}
label_map_path: "위에 작성했던 labelmap.pbtxt 파일 경로"
shuffle: false
num_readers: 1
}
위에 처럼 경로를 다 맞쳐주면 이제 학습할 준비가 완료 된건데 학습할 실행파일도 만들기 귀찮으니
research/object_detection/legarcy 폴더에 가서 train.py를 복사해 온다.
tf.logging.set_verbosity(tf.logging.INFO)
flags = tf.app.flags
flags.DEFINE_string('master', '', 'Name of the TensorFlow master to use.')
flags.DEFINE_integer('task', 0, 'task id')
flags.DEFINE_integer('num_clones', 1, 'Number of clones to deploy per worker.')
flags.DEFINE_boolean('clone_on_cpu', False,
'Force clones to be deployed on CPU. Note that even if '
'set to False (allowing ops to run on gpu), some ops may '
'still be run on the CPU if they have no GPU kernel.')
flags.DEFINE_integer('worker_replicas', 1, 'Number of worker+trainer '
'replicas.')
flags.DEFINE_integer('ps_tasks', 0,
'Number of parameter server tasks. If None, does not use '
'a parameter server.')
flags.DEFINE_string('train_dir', '',
'Directory to save the checkpoints and training summaries.')
flags.DEFINE_string('pipeline_config_path', '',
'Path to a pipeline_pb2.TrainEvalPipelineConfig config '
'file. If provided, other configs are ignored')
flags.DEFINE_string('train_config_path', '',
'Path to a train_pb2.TrainConfig config file.')
flags.DEFINE_string('input_config_path', '',
'Path to an input_reader_pb2.InputReader config file.')
flags.DEFINE_string('model_config_path', '',
'Path to a model_pb2.DetectionModel config file.')
FLAGS = flags.FLAGS
@deprecated(None, 'Use object_detection/model_main.py.')
def main(_):
assert FLAGS.train_dir, '`train_dir` is missing.'
if FLAGS.task == 0: tf.gfile.MakeDirs(FLAGS.train_dir)
if FLAGS.pipeline_config_path:
configs = config_util.get_configs_from_pipeline_file(
FLAGS.pipeline_config_path)
if FLAGS.task == 0:
tf.gfile.Copy(FLAGS.pipeline_config_path,
os.path.join(FLAGS.train_dir, 'pipeline.config'),
overwrite=True)
else:
configs = config_util.get_configs_from_multiple_files(
model_config_path=FLAGS.model_config_path,
train_config_path=FLAGS.train_config_path,
train_input_config_path=FLAGS.input_config_path)
if FLAGS.task == 0:
for name, config in [('model.config', FLAGS.model_config_path),
('train.config', FLAGS.train_config_path),
('input.config', FLAGS.input_config_path)]:
tf.gfile.Copy(config, os.path.join(FLAGS.train_dir, name),
overwrite=True)
model_config = configs['model']
train_config = configs['train_config']
input_config = configs['train_input_config']
model_fn = functools.partial(
model_builder.build,
model_config=model_config,
is_training=True)
def get_next(config):
return dataset_builder.make_initializable_iterator(
dataset_builder.build(config)).get_next()
create_input_dict_fn = functools.partial(get_next, input_config)
env = json.loads(os.environ.get('TF_CONFIG', '{}'))
cluster_data = env.get('cluster', None)
cluster = tf.train.ClusterSpec(cluster_data) if cluster_data else None
task_data = env.get('task', None) or {'type': 'master', 'index': 0}
task_info = type('TaskSpec', (object,), task_data)
# Parameters for a single worker.
ps_tasks = 0
worker_replicas = 1
worker_job_name = 'lonely_worker'
task = 0
is_chief = True
master = ''
if cluster_data and 'worker' in cluster_data:
# Number of total worker replicas include "worker"s and the "master".
worker_replicas = len(cluster_data['worker']) + 1
if cluster_data and 'ps' in cluster_data:
ps_tasks = len(cluster_data['ps'])
if worker_replicas > 1 and ps_tasks < 1:
raise ValueError('At least 1 ps task is needed for distributed training.')
if worker_replicas >= 1 and ps_tasks > 0:
# Set up distributed training.
server = tf.train.Server(tf.train.ClusterSpec(cluster), protocol='grpc',
job_name=task_info.type,
task_index=task_info.index)
if task_info.type == 'ps':
server.join()
return
worker_job_name = '%s/task:%d' % (task_info.type, task_info.index)
task = task_info.index
is_chief = (task_info.type == 'master')
master = server.target
graph_rewriter_fn = None
if 'graph_rewriter_config' in configs:
graph_rewriter_fn = graph_rewriter_builder.build(
configs['graph_rewriter_config'], is_training=True)
trainer.train(
create_input_dict_fn,
model_fn,
train_config,
master,
task,
FLAGS.num_clones,
worker_replicas,
FLAGS.clone_on_cpu,
ps_tasks,
worker_job_name,
is_chief,
FLAGS.train_dir,
graph_hook_fn=graph_rewriter_fn)
if __name__ == '__main__':
tf.app.run()
이제 flag 값으로 아래처럼 traing경로랑 config경로만 주면 학습이 실행 될것이다.
$ python train.py --logtostderr --train_dir=training/ --pipeline_config_path=training/해당.config
그러면 이제 학습이 아래와 같이 실행된다.
이제 학습이 실행되면 잘되고 있는지 모니터링이 필수인데
텐서플로우 에서는 텐서보드라고 아주 편하게 모니터링 하는 툴이 있다.
새로운 터미널을 실행시키고
$ tensorboard --logdir=training
위와 같은식으로 디렉토리를 지정해주면 6006번 포트로 모니터링이 된다.
인터넷 접속프로그램( 크롬브라우저 같은) 주소창에다가
http://localhost:6006 이라고 하면 아래와 같이 모니터링이 된다.
'Python 프로그래밍' 카테고리의 다른 글
파이썬 프로그래밍 Json / XML 제어 하기 (0) | 2023.01.04 |
---|---|
opencv 파이썬 프로그래밍 영상처리 (0) | 2022.12.31 |
파이썬 프로그래밍 Classification EfficientNet (1) | 2022.12.30 |
파이썬 YOLO 텐서플로우 학습하기 (0) | 2022.12.11 |