MNIST 교육을받은 모델의 숫자 인식을 개선하는 방법은 무엇입니까?


12

전처리 및 세분화를 위해 라이브러리를 Java사용 OpenCV하고, KerasMNIST (정확도 0.98)를 인식하도록 인식 된 모델을 사용하여 손자국 된 다중 숫자 인식 작업을 하고 있습니다.

인식은 한 가지 말고는 잘 작동하는 것 같습니다. 네트워크는 종종 하나를 인식하지 못합니다 (숫자 "1"). 전처리 / 잘못된 세그먼트 화 구현으로 인해 발생하는지 또는 표준 MNIST에서 훈련 된 네트워크가 내 테스트 사례처럼 보이는 숫자를 보지 못한 경우 알 수 없습니다.

전처리 및 세그먼트 화 후 문제가되는 숫자는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오해진다 여기에 이미지 설명을 입력하십시오과 같이 분류된다 4.

여기에 이미지 설명을 입력하십시오해진다 여기에 이미지 설명을 입력하십시오과 같이 분류된다 7.

여기에 이미지 설명을 입력하십시오해진다 여기에 이미지 설명을 입력하십시오과 같이 분류된다 4. 등등...

이것은 세분화 프로세스를 개선하여 해결할 수있는 것입니까? 아니면 오히려 훈련 세트를 향상시켜?

편집 : 훈련 세트 (데이터 기능 보강)를 향상시키는 것이 확실히 도움이 될 것입니다. 이미 테스트 중이지만 올바른 전처리 문제는 여전히 남아 있습니다.

내 전처리는 크기 조정, 그레이 스케일로 변환, 이진화, 반전 및 확장으로 구성됩니다. 코드는 다음과 같습니다.

Mat resized = new Mat();
Imgproc.resize(image, resized, new Size(), 8, 8, Imgproc.INTER_CUBIC);

Mat grayscale = new Mat();
Imgproc.cvtColor(resized, grayscale, Imgproc.COLOR_BGR2GRAY);

Mat binImg = new Mat(grayscale.size(), CvType.CV_8U);
Imgproc.threshold(grayscale, binImg, 0, 255, Imgproc.THRESH_OTSU);

Mat inverted = new Mat();
Core.bitwise_not(binImg, inverted);

Mat dilated = new Mat(inverted.size(), CvType.CV_8U);
int dilation_size = 5;
Mat kernel = Imgproc.getStructuringElement(Imgproc.CV_SHAPE_CROSS, new Size(dilation_size, dilation_size));
Imgproc.dilate(inverted, dilated, kernel, new Point(-1,-1), 1);

그런 다음 전처리 된 이미지는 다음과 같이 개별 숫자로 분할됩니다.

List<Mat> digits = new ArrayList<>();
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(preprocessed.clone(), contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

// code to sort contours
// code to check that contour is a valid char

List rects = new ArrayList<>();

for (MatOfPoint contour : contours) {
     Rect boundingBox = Imgproc.boundingRect(contour);
     Rect rectCrop = new Rect(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height);

     rects.add(rectCrop);
}

for (int i = 0; i < rects.size(); i++) {
    Rect x = (Rect) rects.get(i);
    Mat digit = new Mat(preprocessed, x);

    int border = 50;
    Mat result = digit.clone();
    Core.copyMakeBorder(result, result, border, border, border, border, Core.BORDER_CONSTANT, new Scalar(0, 0, 0));

    Imgproc.resize(result, result, new Size(28, 28));
    digits.add(result);
}

1
마스크 또는 마스크 된 원본 회색조 픽셀을 분류에 대한 입력으로 사용하고 있습니까?
Micka

@Micka 나는 전처리 (이진화, 반전, 확장) 버전을 사용하고 있습니다. MNIST 훈련 세트와 일치하는 것. 내 게시물에서 전처리 후 숫자 "1"의 예가 있습니다.
youngpanda

답변:


5

문제가 팽창 과정이라고 생각합니다. 이미지 크기를 정규화하고 싶지만 비율을 깨서는 안되며 한 축 (원하는 다른 축 치수가 최대 크기를 초과하지 않고 가장 큰 크기를 조정할 수있는 축)으로 원하는 최대 크기로 조정하고 채워야한다는 것을 알고 있습니다. 배경색으로 이미지의 나머지 부분. "표준 MNIST는 테스트 사례처럼 보이는 숫자를 보지 못했습니다"라는 것이 아니라 이미지를 다른 훈련 된 숫자 (인식 된 숫자)처럼 보이게합니다.

소스 및 처리 된 이미지의 겹침

이미지 (소스 및 사후 처리)의 올바른 가로 세로 비율을 유지 한 경우 이미지 크기 만 조정 한 것이 아니라 "왜곡"되었음을 알 수 있습니다. 비균질 확장 또는 잘못된 크기 조정의 결과 일 수 있습니다.


@SiR에 약간의 가중치가 있다고 생각합니다. 숫자 리터럴의 종횡비를 변경하지 마십시오.
ZdaR

미안하지만, 나는 잘 따르지 않습니다. 확장 프로세스 또는 크기 조정 프로세스가 문제라고 생각하십니까? 이 줄로 시작하는 이미지의 크기 만 조정합니다 Imgproc.resize(image, resized, new Size(), 8, 8, Imgproc.INTER_CUBIC);. 여기에서 종횡비는 동일하게 유지됩니다. 비율은 어디에서 깨나요?
youngpanda

위의 편집에 대한 @SiR : 예, 나는 단지 이미지의 크기를 조정하지 않고 다른 작업을 적용합니다. 그중 하나는 팽창입니다. 형태는 하나입니다. 또는 이미지를 28x28로 만드는 곳의 최종 크기를 조정 하시겠습니까?
youngpanda

@youngpanda, 당신은 여기에 토론을 찾을 수 있습니다 stackoverflow.com/questions/28525436/… 흥미로운. 당신의 접근 방식이 왜 좋은 결과를 얻지 못하는지에 대한 힌트를 줄 것입니다.
SiR

@SiR 링크에 대해 감사합니다. LeNet에 익숙하지만 다시 읽는 것이 좋습니다
youngpanda

5

이미 게시 된 답변이 있지만 둘 다 이미지 사전 처리 에 대한 실제 질문에 답변하지 않습니다 .

내 차례에는 연구 프로젝트가 잘 수행되는 한 구현에 심각한 문제가 발생하지 않습니다.

그러나 한 가지 주목할 점은 놓칠 수 있습니다. 수학적 형태에는 기본적으로 침식과 팽창이 있습니다. 복잡한 작업 : 기본 작업의 다양한 조합 (예 : 열기 및 닫기) Wikipedia 링크 는 최고의 CV 참조가 아니지만 아이디어를 얻기 위해 시작할 수 있습니다.

보통의 사용에 대한 개선에 대신 침식 개구팽창 대신 개폐 원래 바이너리 이미지는 더 적은 변화 (단, 날카로운 모서리를 청소하거나 갭을 채우는 원하는 효과에 도달 할 때),이 경우에는 사람. 따라서 귀하의 경우 닫기를 확인해야합니다 (이미지 확장과 동일한 커널로의 침식). 1 * 1 커널 (1 픽셀은 이미지의 16 % 이상)로도 확장 할 때 초소형 이미지 8 * 8이 크게 수정되는 경우 큰 이미지에서는 적습니다.

아이디어를 시각화하려면 다음 그림을 참조하십시오 (OpenCV 자습서 : 1 , 2 ).

팽창: 원래의 상징과 확장 된 것

폐쇄: 원래의 상징과 닫힌 것

도움이 되길 바랍니다.


의견을 보내 주셔서 감사합니다! 실제로 그것은 연구 프로젝트 가 아니므 로 문제는 무엇입니까? .. 팽창을 적용 할 때 이미지가 상당히 큽니다. 8x8은 이미지의 크기가 아니며 높이와 너비의 크기 조정 요소입니다. 그러나 여전히 다른 수학적 연산을 시도하는 개선 옵션이 될 수 있습니다. 나는 열고 닫는 것에 대해 몰랐다, 나는 그것을 시험해 볼 것이다! 감사합니다.
youngpanda

내 잘못, 8 * 8을 새로운 크기로 한 것처럼 크기 조정 호출이 잘못되었습니다. 실제 환경에서 OCR을 사용하려는 경우 사용 지역에 일반적인 데이터를 사용하여 원래 인터넷을 학습하는 옵션을 고려해야합니다. 적어도 정확성을 향상시키는 지 확인하십시오. 일반적으로해야합니다.
f4f

확인해야 할 또 다른 사항은 사전 처리 순서입니다 (회색조-> 이진-> 역-> 크기 조정). 크기 조정은 비용이 많이 드는 작업이므로 컬러 이미지에 적용 할 필요가 없습니다. 또한 특정 입력 형식이 있지만 구현하기 어려운 경우 형상 감지없이 비용이 적게 드는 기호 분할을 수행 할 수 있습니다.
f4f

MNIST와 다른 데이터 세트가 있다면 전이 학습을 시도 할 수 있습니다. :) 전처리 순서를 변경하고 다시 연락 드리겠습니다. 감사합니다! 내 문제에 대한 윤곽 감지보다 쉬운 옵션을 아직 찾지 못했습니다 ...
youngpanda

1
확인. 일반적으로 OCR을 사용할 이미지에서 데이터 세트를 직접 수집 할 수 있습니다.
f4f

4

따라서 이전 결과를 기반으로 컴퓨팅 단계의 모든 단계에서 복잡한 접근 방식이 필요합니다. 알고리즘에는 다음 기능이 있습니다.

  1. 이미지 전처리

앞에서 언급했듯이 크기 조정을 적용하면 이미지의 종횡비에 대한 정보가 손실됩니다. 훈련 과정에서 암시 된 것과 동일한 결과를 얻으려면 숫자 이미지를 동일하게 재 처리해야합니다.

고정 크기의 사진으로 이미지를 자르면 더 좋은 방법입니다. 이 변형에서는 훈련 과정 전에 숫자 이미지를 찾아 크기를 조정하는 등고선이 필요하지 않습니다. 그런 다음 자르기 알고리즘을 약간 변경하여 더 잘 인식 할 수 있습니다. 인식을 위해 관련 이미지 프레임의 중심에서 크기를 조정하지 않고 윤곽선을 간단하게 찾고 숫자를 입력하십시오.

또한 이진화 알고리즘에 더주의를 기울여야합니다. 이진화 임계 값이 학습 오류에 미치는 영향을 연구 한 경험이 있습니다. 이것이 매우 중요한 요소라고 말할 수 있습니다. 이 아이디어를 확인하기 위해 다른 이진화 알고리즘을 시도 할 수 있습니다. 예를 들어이 라이브러리 를 사용 하여 대체 이진화 알고리즘을 테스트 할 수 있습니다 .

  1. 학습 알고리즘

인식 품질을 향상 시키려면 훈련 과정에서 교차 검증 을 사용 합니다. 이를 통해 훈련 데이터에 대한 과적 합 문제를 피할 수 있습니다 . 예를 들어 Keras와 함께 사용하는 방법을 설명하는 이 기사를 읽을 수 있습니다 .

때로는 더 높은 정확도 측정이 실제 인식 품질에 대해 아무 것도 말하지 않아 훈련 된 ANN이 훈련 데이터에서 패턴을 찾지 못합니다. 위에서 설명한대로 교육 과정 또는 입력 데이터 집합과 연결되거나 ANN 아키텍처가 선택했을 수 있습니다.

  1. ANN 아키텍처

큰 문제입니다. 더 나은 ANN 아키텍처를 정의하여 작업을 해결하는 방법은 무엇입니까? 그 일을하는 일반적인 방법은 없습니다. 그러나 이상에 더 가까이 갈 수있는 몇 가지 방법이 있습니다. 예를 들어이 책을 읽을 수 있습니다. 문제에 대한 더 나은 비전을 만드는 데 도움이됩니다. 또한 ANN의 숨겨진 레이어 / 요소 수에 맞는 휴리스틱 수식을 찾을 수 있습니다 . 또한 여기 에 약간의 개요가 있습니다.

이것이 도움이되기를 바랍니다.


1. 정확하게 이해하면 고정 크기로자를 수 없으며 여러 자리 숫자의 그림이며 모든 케이스의 크기 / 장소가 다릅니다. 또는 다른 의미입니까? 예, 다른 이진화 방법을 시도하고 매개 변수를 조정했습니다. 2. 실제로 MNIST에 대한 인식은 훌륭하고, 과적 합이 발생하지 않으며, 언급 한 정확도는 테스트 정확도입니다. 네트워크 나 교육에 문제가 없습니다. 3. 모든 링크에 감사드립니다. 물론 아키텍처에 만족합니다. 물론 개선의 여지가 항상 있습니다.
youngpanda

그렇습니다. 그러나 항상 데이터 세트를보다 통합 할 수 있습니다. 귀하의 경우 이미하고있는 것처럼 윤곽선으로 자릿수 이미지를 자르는 것이 좋습니다. 그러나 그 후에는 숫자 이미지의 최대 크기에 따라 숫자 이미지를 x 및 y 스케일로 단일 크기로 확장하는 것이 좋습니다. 이를 위해 숫자 윤곽 영역의 중심을 선호 할 수 있습니다. 훈련 알고리즘에 대한 더 깨끗한 입력 데이터를 제공합니다.
Egor Zamotaev

내가 확장을 건너 뛰어야한다는 것을 의미합니까? 결국 테두리를 적용 할 때 이미 이미지를 중앙에 배치합니다 (각면에 50px). 그 후 MNIST에 필요한 크기이기 때문에 각 숫자를 28x28로 크기 조정하고 있습니다. 28x28의 크기를 다르게 조정할 수 있습니까?
youngpanda

1
그렇습니다, 팽창은 바람직하지 않습니다. 윤곽선의 높이와 너비에 따라 비율이 다를 수 있으므로 여기에서 알고리즘을 개선하는 데 필요한 이유입니다. 최소한 같은 크기의 이미지 크기를 만들어야합니다. 28x28 입력 사진 크기가 있으므로 x 및 y 배율로 동일한 1 : 1 비율의 이미지를 준비해야합니다. 각 그림쪽에 50px 경계선이 아니라 조건을 만족하는 X, Y px 경계선이 있어야합니다. contourSizeX + borderSizeX == contourSizeY + borderSizeY. 그게 다야.
Egor Zamotaev

나는 이미 확장없이 시도했다 (포스트에서 언급하는 것을 잊었다). 결과가 바뀌지 않았습니다 ... 국경 번호는 실험적이었습니다. 이상적으로는 20x20 상자 (데이터 세트에서와 같이 크기가 정규화 됨)에 맞도록 숫자가 필요하고 그 후에 질량 중심을 사용하여 이동합니다.
youngpanda

1

몇 가지 연구와 실험 후에 이미지 전처리 자체가 문제가 아니라는 결론에 도달했습니다 (확장 크기 및 모양과 같은 제안 된 매개 변수를 변경했지만 결과에 중요하지 않았습니다). 그러나 도움이 된 것은 다음 두 가지였습니다.

  1. @ f4f에서 알 수 있듯이 실제 데이터로 내 데이터 세트를 수집해야했습니다. 이것은 이미 엄청난 도움이되었습니다.

  2. 세그먼트 전처리를 중요하게 변경했습니다. 개별 윤곽선을 얻은 후에는 먼저 이미지를 20x20픽셀 상자 에 맞도록 이미지 크기를 정규화합니다 MNIST. 그런 다음 28x28질량 중심을 사용하여 이미지 중간에 상자를 중앙에 배치합니다 (이진 이미지의 경우 두 차원의 평균 값입니다).

물론 겹치거나 연결된 숫자와 같은 어려운 세분화 사례가 여전히 있지만 위의 변경 사항으로 인해 초기 질문에 대답하고 분류 성능이 향상되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.