Google Protocol Buffersの謎性質 AttributeError: 'google.protobuf. {****} ' object has no attribute  {****} 

###見た目上同じでも、同じではない

たとえば、ObjectDetectionAPIにつかうpipeline.configもこのprotocol buffersで書かれているんですが、

```proto:pipeline.config
train_input_reader {
  label_map_path: "PATH_TO_BE_CONFIGURED"
  tf_record_input_reader {
    input_path: "PATH_TO_BE_CONFIGURED"
  }
}

eval_input_reader {
  label_map_path: "PATH_TO_BE_CONFIGURED"
  tf_record_input_reader {
    input_path: "PATH_TO_BE_CONFIGURED"
  }
}
```

というのを見ると、train_input_readerとeval_input_readerは同じ構造に見えるじゃないですか？
そこで、両方のパスを記入しようとして、

```python
pipeline_config_path = 'pipeline.config'

pipeline_config = pipeline_pb2.TrainEvalPipelineConfig()                                                                                                                                                                                                          

with tf.io.gfile.GFile(pipeline_config_path, "r") as f:                                                                                                                                                                                                                     
    proto_str = f.read()                                                                                                                                                                                                                                          
    text_format.Merge(proto_str, pipeline_config)                                                                                                                                                                                                                 

#train_inputを記入
pipeline_config.train_input_reader.label_map_path = "label_map.pbtxt"
pipeline_config.train_input_reader.tf_record_input_reader.input_path[:] = ["train.tfrecords"]

#eval_inputを記入
pipeline_config.eval_input_reader.label_map_path = "label_map.pbtxt"
pipeline_config.eval_input_reader.tf_record_input_reader.input_path[:] = ["eval.tfrecords"]

```
とインプットのパスを記入しようとすると、train_input_readerの方は問題なく通って書き込めるのですが、eval_input_readerはエラーになります。

>google.protobuf.pyext._message.RepeatedCompositeContainer' object has no attribute 'label_map_path'

全く同じ構造に見えて、全く同じアクセスの仕方をしても、片方がエラーになる謎。
（label_map_pathというアトリビュートあるやん。。。）

で、printしてみると、

```python
print(pipeline_config.train_input_reader)
```
>label_map_path: "/content/drive/My Drive/testing/annotated/model_dir/label_map.pbtxt"
tf_record_input_reader {
  input_path: "/content/drive/My Drive/testing/annotated/model_dir/test1.tfrecords"
}

```python
print(pipeline_config.eval_input_reader)
```
>[label_map_path: "/content/drive/My Drive/testing/annotated/model_dir/label_map.pbtxt"
shuffle: false
num_epochs: 1
tf_record_input_reader {
  input_path: "/content/drive/My Drive/testing/annotated/model_dir/test1.tfrecords"
}
]

おわかりいただけただろうか？　eval_input_readerだけ[　]で囲まれている謎。

なので、配列としてアクセスすると、きちんと書き込める。

```python
pipeline_config.eval_input_reader[0].label_map_path = "label_map.pbtxt"
pipeline_config.eval_input_reader[0].tf_record_input_reader.input_path[:] = ["eval.tfrecords"]
```

結果：

```proto:pipeline.config
train_input_reader {
  label_map_path: "label_map.pbtxt"
  tf_record_input_reader {
    input_path: "train.tfrecords"
  }
}

eval_input_reader {
  label_map_path: "label_map.pbtxt"
  tf_record_input_reader {
    input_path: "eval.tfrecords"
  }
}
```

ということで、Protocol Buffersはプリントしてみるとわかりやすい。
あと、単に

```shell
pip install --upgrade protobuf
```
で解決する場合もあるそうです。

ちなみに、Protocol Buffersとは

>プロトコルバッファは、構造化データをシリアル化するためのGoogleの言語中立、プラットフォーム中立、拡張可能なメカニズムです。XMLを考えてみてください。ただし、より小さく、より速く、よりシンプルです。データを一度構造化する方法を定義すると、特別に生成されたソースコードを使用して、さまざまなデータストリームとの間で、さまざまな言語を使用して構造化データを簡単に読み書きできます。




とのことです。google公式より。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)

🐣
****
Request for work:
rockyshikoku@gmail.com


We send information related to machine learning.
Twitter
Request for work:
rockyshikoku@gmail.com