TensorFlow对象检测API奇怪的行为

时间:2017-07-11 09:03:09

标签: python machine-learning tensorflow classification object-detection

我正在玩TensorFlow的全新Object Detection API并决定在其他一些公开的数据集上进行训练。

我碰巧偶然发现了this食品杂货数据集,其中包括超市货架上各种品牌香烟盒的图像,以及一个文本文件,其中列出了每个图像中每个香烟盒的边界框。数据集中已经标注了10个主要品牌,所有其他品牌都属于第11个"杂项"类别。

我关注他们的tutorial并设法在此数据集上训练模型。由于处理能力的限制,我只使用了数据集的三分之一,并进行了70:30分割,用于训练和测试数据。我使用了faster_rcnn_resnet101模型。配置文件中的所有参数与TF提供的默认参数相同。

在16491个全局步骤之后,我在一些图像上测试了模型,但我对结果不太满意 -

无法在顶层检测到Camels,而在其他图像中检测到该产品

为什么它没能检测到顶行的万宝路?

我遇到的另一个问题是模型从未检测到除标签1之外的任何其他标签

没有从训练数据中检测到产品的裁剪实例

即使在负片图像中,它也可以99%的置信度检测到香烟盒!

有人可以帮我解决出错的问题吗?我该怎么做才能提高准确度?为什么它会检测到属于第1类的所有产品,尽管我已经提到总共有11个类?

修改添加了我的标签地图:

path_mylibrary_a_LDADD = cfile.la

noinst_LTLIBRARIES = cfile.la
cfile_la_CPPFLAGS = -std=c11
cfile_la_SOURCES = cfile.c

5 个答案:

答案 0 :(得分:13)

所以我想我弄清楚发生了什么。我对数据集进行了一些分析,发现它偏向于类别1的对象。

这是每个类别的频率分布,从1到11(基于0的索引)

public class Tab1 extends Fragment {

PendingPickupBEAN pendingPickup=new PendingPickupBEAN();
public static final List<PendingPickupBEAN> refer=new ArrayList<PendingPickupBEAN>();
ListView listview;
CustomListView customListView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /*listview= (ListView) findViewById(R.id.listTab1);
    customListView = new CustomListView(getContext(),R.layout.list_item,DashboardActivity.listBeanobj);

    Log.e(TAG,"=======CUSTOM LIST VIEW ========");
    listview.setAdapter(customListView);*/


}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

   // final ArrayList<PendingPickupBEAN> listPending = (ArrayList<PendingPickupBEAN>) getIntent().getSerializableExtra("ARRAYLIST");

  Log.e(TAG,"Pending piclup list : listbeanobj " + DashboardActivity.listBeanobj.size());

    View view= inflater.inflate(R.layout.activity_tab1, container, false);
    return  view;


    listview=(ListView) view.findViewById(R.id.listTab1);
    customListView = new CustomListView(getContext(),R.layout.list_item,DashboardActivity.listBeanobj);

    Log.e(TAG,"=======CUSTOM LIST VIEW ========");
    listview.setAdapter(customListView);


}

public class CustomListView  extends ArrayAdapter<PendingPickupBEAN> {

   /* ArrayAdapter<PendingPickupBEAN> adapter=new ArrayAdapter<PendingPickupBEAN>
            (Tab1.this,R.layout.list_item_accepted,refer);*/

    ArrayAdapter<PendingPickupBEAN> adapter=new ArrayAdapter<PendingPickupBEAN>
            (getContext(),R.layout.list_item_accepted,refer);
    Context context;
    LayoutInflater inflater;
    List<PendingPickupBEAN> obj;

    public CustomListView(Context context, int resourceId,
                          List<PendingPickupBEAN> obj) {
        super(context,resourceId,obj);
        this.context=context;
        this.obj=obj;
        inflater=LayoutInflater.from(context);


    }

    private class ViewHolder {
        TextView txt_pickupID;
        TextView txt_address;
        Button btn_Accept;
        Button btn_Decline;


    }

    public View getView(final int position, View view, final ViewGroup parent) {
        final CustomListView.ViewHolder holder;

        if (view == null) {
            holder = new CustomListView.ViewHolder();
            view = inflater.inflate(R.layout.list_item, null);



            holder.txt_pickupID=(TextView) view.findViewById(R.id.pickupID);
            holder.txt_address = (TextView) view.findViewById(R.id.address);
            holder.btn_Accept = (Button) view.findViewById(R.id.btnAccept);
            holder.btn_Decline = (Button) view.findViewById(R.id.btnDecline);

            holder.txt_pickupID = (TextView) view.findViewById(R.id.pickupID);
            holder.txt_address = (TextView) view.findViewById(R.id.address);
            holder.btn_Accept = (Button) view.findViewById(R.id.btnAccept);
            holder.btn_Decline = (Button) view.findViewById(R.id.btnDecline);


            view.setTag(holder);
        } else {
            holder = (CustomListView.ViewHolder) view.getTag();
        }

        holder.txt_pickupID.setText(obj.get(position).getPickupID());
        holder.txt_address.setText(obj.get(position).getAddress());



        holder.btn_Accept.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                holder.btn_Decline.setText("FORWARD");
                holder.btn_Accept.setText("ACCEPTED");
                holder.btn_Accept.setBackgroundResource(R.color.colorAccept);

                pendingPickup.setPickupID(holder.txt_pickupID.getText().toString());
                Log.d(TAG, "= chk value isn't set or not====" + pendingPickup.getPickupID());
                pendingPickup.setAccept_Decline(holder.btn_Accept.getText().toString());
                Log.d(TAG, "== chk value isn't set or not===" + pendingPickup.getAccept_Decline());

                //===============
                String value = holder.txt_pickupID.getText().toString();
                String buttonText = holder.btn_Accept.getText().toString();
                Log.d(TAG, "===" + buttonText + "  " + value);
                new ExecuteTask().execute();
                //=============

                PendingPickupBEAN beanOBJ = new PendingPickupBEAN();

                beanOBJ.setPickupID(holder.txt_pickupID.getText().toString());
                beanOBJ.setAccept_Decline(holder.btn_Accept.getText().toString());
                refer.add(beanOBJ);

                //refer.add(holder.txt_pickupID.getText().toString());
                Log.d(TAG,"=======Size of refer array in same clas button====" +refer.size());

                adapter.notifyDataSetChanged();

            }
        });


        holder.btn_Decline.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                AlertDialog.Builder builder=new AlertDialog.Builder(getContext());
                builder.setTitle("Alert!!!");
                builder.setMessage("Are you Sure?");

                builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                        holder.btn_Accept.setEnabled(false);
                        holder.btn_Decline.setText("DECLINED");
                        holder.btn_Decline.setBackgroundResource(R.color.colorDecline);
                        holder.btn_Decline.setClickable(true);
                      //  finish();
                    }
                });

                builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                        holder.btn_Accept.setEnabled(true);
                        holder.btn_Decline.setText("DECLINE");
                                                    holder.btn_Decline.setClickable(true);
                    }
                });
                AlertDialog alertDialog=builder.create();
                alertDialog.show();

               /* value = holder.txt_pickupID.getText().toString();
                buttonText = holder.btn_Decline.getText().toString();
                Log.d(TAG, "===" + buttonText + "  " + value);*/

                pendingPickup.setPickupID(holder.txt_pickupID.getText().toString());
                Log.d(TAG, "= chk value isn't set or not====" + pendingPickup.getPickupID());
                pendingPickup.setAccept_Decline(holder.btn_Decline.getText().toString());
                Log.d(TAG, "== chk value isn't set or not===" + pendingPickup.getAccept_Decline());

                new ExecuteTask().execute();
            }

        });


        return view;

    }

}

public class ExecuteTask extends AsyncTask<Void,Void,Void> {

    int updateResponse;

    @Override
    protected Void doInBackground(Void... params) {


        String[] values = { pendingPickup.getAccept_Decline(), pendingPickup.getPickupID()};


        Log.d(TAG,"ACCEPT / DECLINE== "+ pendingPickup.getAccept_Decline());

        Log.d(TAG,"PICKUPID ===" + pendingPickup.getPickupID());


        try {
            HttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(
                    JsonURLPath.JSONURL + "/setPickupAcceptDeclineUpdate");

            List<NameValuePair> list = new ArrayList<NameValuePair>();

            list.add(new BasicNameValuePair("accept_decline", values[0]));
            list.add(new BasicNameValuePair("pickupid", values[1]));


            httpPost.setEntity(new UrlEncodedFormEntity(list));
            HttpResponse response = httpClient.execute(httpPost);
            updateResponse = response.getStatusLine().getStatusCode();



        } catch (Exception e) {
            Log.e(TAG, " in Catch block ");
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void onPostExecute(Void rs) {
        Log.e(TAG, "1----------post execute--");
        super.onPostExecute(rs);

    }


}

}

我猜模型正在达到局部最小值,只是将所有内容标记为类别1就足够了。

关于没有检测到一些盒子的问题:我再次尝试了培训,但这次我没有区分品牌。相反,我试图教模型香烟盒是什么。它仍然没有检测到所有的盒子。

然后我决定裁剪输入图像并将其作为输入提供。只是为了看看结果是否有所改善而且确实如此!

事实证明,输入图像的尺寸远大于模型所接受的600 x 1024。因此,它将这些图像缩小到600 x 1024,这意味着香烟盒正在丢失它们的细节:)

所以,我决定测试原始模型,该模型在裁剪后的图像上进行了所有课程的训练,它就像一个魅力:)

Original image

这是原始图像上模型的输出

Top left corner cropped from original image

当我裁剪出左上角的四分之一并将其作为输入时,这是模型的输出。

感谢所有帮助过的人!并祝贺TensorFlow团队为API做出了惊人的工作:)现在每个人都可以训练对象检测模型!

答案 1 :(得分:4)

数据集中有多少张图片?您拥有的训练数据越多,API执行的越多。我尝试每班约20张图像进行训练,准确度非常差。我几乎面临你上面提到的所有问题。当我生成更多数据时,准确度大大提高。

PS:抱歉,我没有评论,因为我没有足够的声誉

答案 2 :(得分:2)

也许现在为时已晚,但如果将来有人对此发表意见,我想发表评论:

不幸的是,TF文档并不是最好的,在找到原因之前,我为此付出了很多努力。建立模型的方式是,每张图片最多允许x个预测值。在您的情况下,我认为是20岁。您可以通过编辑原始照片来轻松检验我的假设:enter image description here

很明显,在实际绘制框之前,您应该会看到一些更好的结果。

非常讨厌的限制。

答案 3 :(得分:2)

有些参数需要配置,例如:

train_input_reader {
  max_number_of_boxes: 1000
}

eval_input_reader {
  max_number_of_boxes: 1000
}

它们非常重要。默认情况下,它们设置为100。

答案 4 :(得分:0)

看来,数据集大小相当小。 Resnet是一个大型网络,需要更多数据才能正常训练。

怎么做:

  1. 增加数据集大小
  2. 使用预先训练好的网络并对数据集进行微调(您可能已经这样做了)
  3. 使用数据扩充(调整大小,模糊,......;翻转可能不适合此数据集)。