>  기사  >  백엔드 개발  >  시퀀스 주석, 손으로 쓴 소문자 OCR 데이터 세트, 양방향 RNN

시퀀스 주석, 손으로 쓴 소문자 OCR 데이터 세트, 양방향 RNN

巴扎黑
巴扎黑원래의
2017-06-23 14:55:221953검색

시퀀스 라벨링, 입력 시퀀스의 각 프레임에 대한 카테고리 예측. OCR(광학 문자 인식 광학 문자 인식).

MIT 음성 언어 시스템 연구 그룹 Rob Kassel이 수집하고 Stanford University 인공 지능 연구소 Ben Taskar가 전처리한 OCR 데이터 세트(http://ai.stanford.edu/~btaskar/ocr/)에는 수많은 개인 정보가 포함되어 있습니다. 손으로 쓴 소문자, 각 샘플은 16X8 픽셀 바이너리 이미지에 해당합니다. 워드 라인은 시퀀스를 결합하고 시퀀스는 단어에 해당합니다. 14자 이하의 6800단어입니다. gzip으로 압축되었으며 콘텐츠는 탭으로 구분된 텍스트 파일입니다. Python csv 모듈은 직접 읽습니다. 파일의 각 줄에는 하나의 정규화된 문자 속성, ID 번호, 라벨, 픽셀 값, 다음 문자 ID 번호 등이 있습니다.

다음 문자 ID 값을 기준으로 정렬하고 각 단어 문자를 올바른 순서로 읽습니다. 다음 ID 해당 필드가 설정되지 않을 때까지 문자를 수집합니다. 새 시퀀스를 읽습니다. 대상 문자와 데이터 픽셀을 읽은 후 시퀀스 객체를 0개의 이미지로 채웁니다. 이 이미지는 두 개의 더 큰 대상 문자의 모든 픽셀 데이터의 NumPy 배열에 포함될 수 있습니다.

Softmax 레이어는 시간 단계 간에 공유됩니다. 데이터 및 대상 배열에는 각 대상 문자에 대한 하나의 이미지 프레임인 시퀀스가 ​​포함됩니다. RNN 확장, 각 문자 출력에 소프트맥스 분류기를 추가합니다. 분류기는 전체 시퀀스가 ​​아닌 각 데이터 프레임에 대한 예측을 평가합니다. 시퀀스 길이를 계산합니다. 소프트맥스 레이어가 모든 프레임에 추가됩니다. 즉, 여러 다른 분류자가 모든 프레임에 추가되거나 모든 프레임이 동일한 분류자를 공유합니다. 공유 분류기를 사용하면 훈련 중에 훈련 단어의 각 문자에 대해 가중치가 더 많이 조정됩니다. 완전히 연결된 레이어 가중치 행렬 차원 Batch_size*in_size*out_size. 이제 두 개의 입력 차원인 Batch_size 및 Sequence_steps에서 가중치 행렬을 업데이트해야 합니다. 입력(RNN 출력 활동 값)을 배치_크기*순서_단계*in_size 모양으로 평면화합니다. 가중치 행렬은 더 큰 데이터 배치가 됩니다. 결과는 평평하지 않습니다.

비용 함수, 시퀀스의 각 프레임에는 해당 차원에서 평균을 낸 예측 대상 쌍이 있습니다. 텐서 길이(시퀀스의 최대 길이)에 따라 정규화된 tf.reduce_mean은 사용할 수 없습니다. 실제 시퀀스 길이에 따라 정규화하고 tf.reduce_sum 및 나누기 연산 평균을 수동으로 호출해야 합니다.

손실 함수인 tf.argmax는 축 1이 아닌 축 2에 대한 것이며, 각 프레임이 채워지고 평균은 시퀀스의 실제 길이를 기준으로 계산됩니다. tf.reduce_mean은 배치 데이터에 있는 모든 단어의 평균을 취합니다.

TensorFlow의 자동 도함수 계산은 시퀀스 분류에 동일한 최적화 작업을 사용할 수 있으며 새로운 비용 함수만 대체하면 됩니다. 훈련 발산을 방지하고 부정적인 영향을 피하기 위해 모든 RNN 그래디언트를 잘라냅니다.

모델을 훈련하고, get_sataset은 필기 이미지, 전처리, 소문자의 원-핫 인코딩 벡터를 다운로드합니다. 데이터의 순서를 무작위로 바꾸고 훈련 세트와 테스트 세트로 나눕니다.

단어의 인접한 문자 사이에는 종속 관계(또는 상호 정보)가 있으며 RNN은 동일한 단어의 모든 입력 정보를 암시적 활동 값에 저장합니다. 처음 몇 글자의 분류를 위해 네트워크는 추가 정보를 추론하기 위한 입력량이 많지 않으며 양방향 RNN이 단점을 극복합니다.
두 개의 RNN은 입력 순서를 관찰합니다. 하나는 일반적인 순서로 왼쪽 끝에서 단어를 읽고, 다른 하나는 반대 순서로 오른쪽 끝에서 단어를 읽습니다. 각 시간 단계마다 두 개의 출력 활동 값이 얻어집니다. 공유 소프트맥스 레이어로 보내기 전에 접합합니다. 분류자는 각 문자에서 완전한 단어 정보를 얻습니다. tf.modle.rnn.bidirection_rnn이 구현되었습니다.

양방향 RNN을 구현하세요. 예측 속성을 두 가지 기능으로 나누고 더 적은 내용에 집중하세요. _shared_softmax 함수는 함수 텐서 데이터를 전달하여 입력 크기를 추론합니다. 다른 아키텍처 기능을 재사용하면 동일한 평면화 기술이 모든 단계에서 동일한 소프트맥스 레이어를 공유합니다. rnn.dynamic_rnn은 두 개의 RNN을 생성합니다.
시퀀스 반전은 새로운 역전파 RNN 연산을 구현하는 것보다 쉽습니다. tf.reverse_sequence 함수는 프레임 데이터의 시퀀스_길이 프레임을 반전시킵니다. 데이터 흐름 다이어그램 노드에는 이름이 있습니다. 범위 매개변수는 rnn_dynamic_cell 변수 범위 이름이고 기본값은 RNN입니다. 두 매개변수는 RNN마다 다르며 다른 도메인이 필요합니다.
역방향 시퀀스는 역방향 RNN에 공급되고 네트워크 출력은 역전되어 순방향 출력과 정렬됩니다. RNN 뉴런 출력 차원을 따라 두 개의 텐서를 연결하고 반환합니다. 양방향 RNN 모델의 성능이 더 좋습니다.

    import gzipimport csvimport numpy as npfrom helpers import downloadclass OcrDataset:

        URL = 'http://ai.stanford.edu/~btaskar/ocr/letter.data.gz'def __init__(self, cache_dir):
            path = download(type(self).URL, cache_dir)
            lines = self._read(path)
            data, target = self._parse(lines)
            self.data, self.target = self._pad(data, target)

        @staticmethoddef _read(filepath):
            with gzip.open(filepath, 'rt') as file_:
                reader = csv.reader(file_, delimiter='\t')
                lines = list(reader)return lines

        @staticmethoddef _parse(lines):
            lines = sorted(lines, key=lambda x: int(x[0]))
            data, target = [], []
            next_ = Nonefor line in lines:if not next_:
                    data.append([])
                    target.append([])else:assert next_ == int(line[0])
                next_ = int(line[2]) if int(line[2]) > -1 else None
                pixels = np.array([int(x) for x in line[6:134]])
                pixels = pixels.reshape((16, 8))
                data[-1].append(pixels)
                target[-1].append(line[1])return data, target

        @staticmethoddef _pad(data, target):
            max_length = max(len(x) for x in target)
            padding = np.zeros((16, 8))
            data = [x + ([padding] * (max_length - len(x))) for x in data]
            target = [x + ([''] * (max_length - len(x))) for x in target]return np.array(data), np.array(target)import tensorflow as tffrom helpers import lazy_propertyclass SequenceLabellingModel:def __init__(self, data, target, params):
            self.data = data
            self.target = target
            self.params = params
            self.prediction
            self.cost
            self.error
            self.optimize

        @lazy_propertydef length(self):
            used = tf.sign(tf.reduce_max(tf.abs(self.data), reduction_indices=2))
            length = tf.reduce_sum(used, reduction_indices=1)
            length = tf.cast(length, tf.int32)return length

        @lazy_propertydef prediction(self):
            output, _ = tf.nn.dynamic_rnn(
                tf.nn.rnn_cell.GRUCell(self.params.rnn_hidden),
                self.data,
                dtype=tf.float32,
                sequence_length=self.length,
            )# Softmax layer.max_length = int(self.target.get_shape()[1])
            num_classes = int(self.target.get_shape()[2])
            weight = tf.Variable(tf.truncated_normal(
                [self.params.rnn_hidden, num_classes], stddev=0.01))
            bias = tf.Variable(tf.constant(0.1, shape=[num_classes]))# Flatten to apply same weights to all time steps.output = tf.reshape(output, [-1, self.params.rnn_hidden])
            prediction = tf.nn.softmax(tf.matmul(output, weight) + bias)
            prediction = tf.reshape(prediction, [-1, max_length, num_classes])return prediction

        @lazy_propertydef cost(self):# Compute cross entropy for each frame.cross_entropy = self.target * tf.log(self.prediction)
            cross_entropy = -tf.reduce_sum(cross_entropy, reduction_indices=2)
            mask = tf.sign(tf.reduce_max(tf.abs(self.target), reduction_indices=2))
            cross_entropy *= mask# Average over actual sequence lengths.cross_entropy = tf.reduce_sum(cross_entropy, reduction_indices=1)
            cross_entropy /= tf.cast(self.length, tf.float32)return tf.reduce_mean(cross_entropy)

        @lazy_propertydef error(self):
            mistakes = tf.not_equal(
                tf.argmax(self.target, 2), tf.argmax(self.prediction, 2))
            mistakes = tf.cast(mistakes, tf.float32)
            mask = tf.sign(tf.reduce_max(tf.abs(self.target), reduction_indices=2))
            mistakes *= mask# Average over actual sequence lengths.mistakes = tf.reduce_sum(mistakes, reduction_indices=1)
            mistakes /= tf.cast(self.length, tf.float32)return tf.reduce_mean(mistakes)

        @lazy_propertydef optimize(self):
            gradient = self.params.optimizer.compute_gradients(self.cost)try:
                limit = self.params.gradient_clipping
                gradient = [
                    (tf.clip_by_value(g, -limit, limit), v)if g is not None else (None, v)for g, v in gradient]except AttributeError:print('No gradient clipping parameter specified.')
            optimize = self.params.optimizer.apply_gradients(gradient)return optimizeimport randomimport tensorflow as tfimport numpy as npfrom helpers import AttrDictfrom OcrDataset import OcrDatasetfrom SequenceLabellingModel import SequenceLabellingModelfrom batched import batched

    params = AttrDict(
        rnn_cell=tf.nn.rnn_cell.GRUCell,
        rnn_hidden=300,
        optimizer=tf.train.RMSPropOptimizer(0.002),
        gradient_clipping=5,
        batch_size=10,
        epochs=5,
        epoch_size=50)def get_dataset():
        dataset = OcrDataset('./ocr')# Flatten images into vectors.dataset.data = dataset.data.reshape(dataset.data.shape[:2] + (-1,))# One-hot encode targets.target = np.zeros(dataset.target.shape + (26,))for index, letter in np.ndenumerate(dataset.target):if letter:
                target[index][ord(letter) - ord('a')] = 1dataset.target = target# Shuffle order of examples.order = np.random.permutation(len(dataset.data))
        dataset.data = dataset.data[order]
        dataset.target = dataset.target[order]return dataset# Split into training and test data.dataset = get_dataset()
    split = int(0.66 * len(dataset.data))
    train_data, test_data = dataset.data[:split], dataset.data[split:]
    train_target, test_target = dataset.target[:split], dataset.target[split:]# Compute graph._, length, image_size = train_data.shape
    num_classes = train_target.shape[2]
    data = tf.placeholder(tf.float32, [None, length, image_size])
    target = tf.placeholder(tf.float32, [None, length, num_classes])
    model = SequenceLabellingModel(data, target, params)
    batches = batched(train_data, train_target, params.batch_size)

    sess = tf.Session()
    sess.run(tf.initialize_all_variables())for index, batch in enumerate(batches):
        batch_data = batch[0]
        batch_target = batch[1]
        epoch = batch[2]if epoch >= params.epochs:breakfeed = {data: batch_data, target: batch_target}
        error, _ = sess.run([model.error, model.optimize], feed)print('{}: {:3.6f}%'.format(index + 1, 100 * error))

    test_feed = {data: test_data, target: test_target}
    test_error, _ = sess.run([model.error, model.optimize], test_feed)print('Test error: {:3.6f}%'.format(100 * error))import tensorflow as tffrom helpers import lazy_propertyclass BidirectionalSequenceLabellingModel:def __init__(self, data, target, params):
            self.data = data
            self.target = target
            self.params = params
            self.prediction
            self.cost
            self.error
            self.optimize

        @lazy_propertydef length(self):
            used = tf.sign(tf.reduce_max(tf.abs(self.data), reduction_indices=2))
            length = tf.reduce_sum(used, reduction_indices=1)
            length = tf.cast(length, tf.int32)return length

        @lazy_propertydef prediction(self):
            output = self._bidirectional_rnn(self.data, self.length)
            num_classes = int(self.target.get_shape()[2])
            prediction = self._shared_softmax(output, num_classes)return predictiondef _bidirectional_rnn(self, data, length):
            length_64 = tf.cast(length, tf.int64)
            forward, _ = tf.nn.dynamic_rnn(
                cell=self.params.rnn_cell(self.params.rnn_hidden),
                inputs=data,
                dtype=tf.float32,
                sequence_length=length,
                scope='rnn-forward')
            backward, _ = tf.nn.dynamic_rnn(
            cell=self.params.rnn_cell(self.params.rnn_hidden),
            inputs=tf.reverse_sequence(data, length_64, seq_dim=1),
            dtype=tf.float32,
            sequence_length=self.length,
            scope='rnn-backward')
            backward = tf.reverse_sequence(backward, length_64, seq_dim=1)
            output = tf.concat(2, [forward, backward])return outputdef _shared_softmax(self, data, out_size):
            max_length = int(data.get_shape()[1])
            in_size = int(data.get_shape()[2])
            weight = tf.Variable(tf.truncated_normal(
                [in_size, out_size], stddev=0.01))
            bias = tf.Variable(tf.constant(0.1, shape=[out_size]))# Flatten to apply same weights to all time steps.flat = tf.reshape(data, [-1, in_size])
            output = tf.nn.softmax(tf.matmul(flat, weight) + bias)
            output = tf.reshape(output, [-1, max_length, out_size])return output

        @lazy_propertydef cost(self):# Compute cross entropy for each frame.cross_entropy = self.target * tf.log(self.prediction)
            cross_entropy = -tf.reduce_sum(cross_entropy, reduction_indices=2)
            mask = tf.sign(tf.reduce_max(tf.abs(self.target), reduction_indices=2))
            cross_entropy *= mask# Average over actual sequence lengths.cross_entropy = tf.reduce_sum(cross_entropy, reduction_indices=1)
            cross_entropy /= tf.cast(self.length, tf.float32)return tf.reduce_mean(cross_entropy)

        @lazy_propertydef error(self):
            mistakes = tf.not_equal(
                tf.argmax(self.target, 2), tf.argmax(self.prediction, 2))
            mistakes = tf.cast(mistakes, tf.float32)
            mask = tf.sign(tf.reduce_max(tf.abs(self.target), reduction_indices=2))
            mistakes *= mask# Average over actual sequence lengths.mistakes = tf.reduce_sum(mistakes, reduction_indices=1)
            mistakes /= tf.cast(self.length, tf.float32)return tf.reduce_mean(mistakes)

        @lazy_propertydef optimize(self):
            gradient = self.params.optimizer.compute_gradients(self.cost)try:
                limit = self.params.gradient_clipping
                gradient = [
                    (tf.clip_by_value(g, -limit, limit), v)if g is not None else (None, v)for g, v in gradient]except AttributeError:print('No gradient clipping parameter specified.')
            optimize = self.params.optimizer.apply_gradients(gradient)return optimize

참조:
"TensorFlow Practice for Machine Intelligence"

WeChat에서 소통할 수 있도록 저를 추가해 주셔서 감사합니다: qingxingfengzi
내 WeChat 공개 계정: qingxingfengzigz
내 아내 Zhang Xingqing의 WeChat 공개 계정: qingqingfeifangz

위 내용은 시퀀스 주석, 손으로 쓴 소문자 OCR 데이터 세트, 양방향 RNN의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.