我正在玩TensorFlow的全新Object Detection API并决定在其他一些公开的数据集上进行训练。
我碰巧偶然发现了this食品杂货数据集,其中包括超市货架上各种品牌香烟盒的图像,以及一个文本文件,其中列出了每个图像中每个香烟盒的边界框。数据集中已经标注了10个主要品牌,所有其他品牌都属于第11个"杂项"类别。
我关注他们的tutorial并设法在此数据集上训练模型。由于处理能力的限制,我只使用了数据集的三分之一,并进行了70:30分割,用于训练和测试数据。我使用了faster_rcnn_resnet101模型。配置文件中的所有参数与TF提供的默认参数相同。
在16491个全局步骤之后,我在一些图像上测试了模型,但我对结果不太满意 -
我遇到的另一个问题是模型从未检测到除标签1之外的任何其他标签
没有从训练数据中检测到产品的裁剪实例
即使在负片图像中,它也可以99%的置信度检测到香烟盒!
有人可以帮我解决出错的问题吗?我该怎么做才能提高准确度?为什么它会检测到属于第1类的所有产品,尽管我已经提到总共有11个类?
修改添加了我的标签地图:
path_mylibrary_a_LDADD = cfile.la
noinst_LTLIBRARIES = cfile.la
cfile_la_CPPFLAGS = -std=c11
cfile_la_SOURCES = cfile.c
答案 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,这意味着香烟盒正在丢失它们的细节:)
所以,我决定测试原始模型,该模型在裁剪后的图像上进行了所有课程的训练,它就像一个魅力:)
这是原始图像上模型的输出
当我裁剪出左上角的四分之一并将其作为输入时,这是模型的输出。
感谢所有帮助过的人!并祝贺TensorFlow团队为API做出了惊人的工作:)现在每个人都可以训练对象检测模型!
答案 1 :(得分:4)
数据集中有多少张图片?您拥有的训练数据越多,API执行的越多。我尝试每班约20张图像进行训练,准确度非常差。我几乎面临你上面提到的所有问题。当我生成更多数据时,准确度大大提高。
PS:抱歉,我没有评论,因为我没有足够的声誉
答案 2 :(得分:2)
也许现在为时已晚,但如果将来有人对此发表意见,我想发表评论:
不幸的是,TF文档并不是最好的,在找到原因之前,我为此付出了很多努力。建立模型的方式是,每张图片最多允许x个预测值。在您的情况下,我认为是20岁。您可以通过编辑原始照片来轻松检验我的假设:
很明显,在实际绘制框之前,您应该会看到一些更好的结果。
非常讨厌的限制。
答案 3 :(得分:2)
有些参数需要配置,例如:
train_input_reader {
max_number_of_boxes: 1000
}
eval_input_reader {
max_number_of_boxes: 1000
}
它们非常重要。默认情况下,它们设置为100。
答案 4 :(得分:0)
看来,数据集大小相当小。 Resnet是一个大型网络,需要更多数据才能正常训练。
怎么做: