ValueError:无法为形状为'(?,621)'的Tensor u'Placeholder_1:0'输入形状(50,807)的值

时间:2019-03-11 08:39:42

标签: python tensorflow deep-learning conv-neural-network

我正在尝试为英国车牌(https://github.com/matthewearl/deep-anpr)到包含阿拉伯字母的摩洛哥车牌实施Tensorflow神经网络,添加utf-8编码后,我能够生成包含阿拉伯车牌的数据集字母,但是当我尝试进行训练时,最终会出现张量形状错误。这是train_1.py代码

    #!/usr/bin/python
# -*- coding: utf-8 -*-
_all__ = (
    'train',
)


import functools
import glob
import itertools
import multiprocessing
import random
import sys
import time

import cv2
import numpy
import tensorflow as tf

import common
import gen
import model

DIGITS = "0123456789"
DIGITS_E = "0 1 2 3 4 5 6 7 8 9"
DIGITS_E1 = "0123456789 "
DIGITS_0 = "123456789"
BARRE = "|"
LETTERS = "وهدجبأ"
CHARS = LETTERS + DIGITS + BARRE + DIGITS_E + DIGITS_0 + DIGITS_E1 

def generate_code_train():
    matricule =  "{}{} {}{} {}{} {}{}{}{}".format(
            random.choice(DIGITS_0),
            random.choice(DIGITS),
            random.choice(DIGITS),
            random.choice(DIGITS),
            random.choice(DIGITS_E1),
            random.choice(BARRE),
            random.choice(LETTERS),
            random.choice(BARRE),
            random.choice(DIGITS_0),
            random.choice(DIGITS_E1))

    #matricule = matricule.decode("utf-8")

    return matricule


def code_to_vec(p, code):
    def char_to_vec(c):
        y = numpy.zeros((len(CHARS),))
        y[CHARS.index(c)] = 1.0
        return y
    code = generate_code_train()
    c = numpy.vstack([char_to_vec(c) for c in code])

    return numpy.concatenate([[1. if p else 0], c.flatten()])


def read_data(img_glob):
    for fname in sorted(glob.glob(img_glob)):
        im = cv2.imread(fname)[:, :, 0].astype(numpy.float32) / 255.
        code = fname.split("/")[1][9:19]
        p = fname.split("/")[1][20] == '1'
        yield im, code_to_vec(p, code)


def unzip(b):
    xs, ys = zip(*b)
    xs = numpy.array(xs)
    ys = numpy.array(ys)
    return xs, ys


def batch(it, batch_size):
    out = []
    for x in it:
        out.append(x)
        if len(out) == batch_size:
            yield out
            out = []
    if out:
        yield out


def mpgen(f):
    def main(q, args, kwargs):
        try:
            for item in f(*args, **kwargs):
                q.put(item)
        finally:
            q.close()

    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        q = multiprocessing.Queue(3) 
        proc = multiprocessing.Process(target=main,
                                       args=(q, args, kwargs))
        proc.start()
        try:
            while True:
                item = q.get()
                yield item
        finally:
            proc.terminate()
            proc.join()

    return wrapped


#@mpgen
def read_batches(batch_size):
    g = gen.generate_ims()
    def gen_vecs():
        for im, c, p in itertools.islice(g, batch_size):
            yield im, code_to_vec(p, c)

    while True:
        yield unzip(gen_vecs())


def get_loss(y, y_):
    # Calculate the loss from digits being incorrect.  Don't count loss from
    # digits that are in non-present plates.
    digits_loss = tf.nn.softmax_cross_entropy_with_logits(
                                          logits=tf.reshape(y[:, 1:],
                                                     [-1, len(CHARS)]),
                                          labels=tf.reshape(y_[:, 1:],
                                                     [-1, len(CHARS)]))
    digits_loss = tf.reshape(digits_loss, [-1, 10]) #7 changed to 10
    digits_loss = tf.reduce_sum(digits_loss, 1)
    digits_loss *= (y_[:, 0] != 0)
    digits_loss = tf.reduce_sum(digits_loss)

    # Calculate the loss from presence indicator being wrong.
    presence_loss = tf.nn.sigmoid_cross_entropy_with_logits(
                                                          logits=y[:, :1], labels=y_[:, :1])
    presence_loss = 10 * tf.reduce_sum(presence_loss) # 7 changed to 10

    return digits_loss, presence_loss, digits_loss + presence_loss


def train(learn_rate, report_steps, batch_size, initial_weights):
    """
    Train the network.
    The function operates interactively: Progress is reported on stdout, and
    training ceases upon `KeyboardInterrupt` at which point the learned weights
    are saved to `weights.npz`, and also returned.
    :param learn_rate:
        Learning rate to use.
    :param report_steps:
        Every `report_steps` batches a progress report is printed.
    :param batch_size:
        The size of the batches used for training.
    :param initial_weights:
        (Optional.) Weights to initialize the network with.
    :return:
        The learned network weights.
    """
    x, y, params = model.get_training_model()

    y_ = tf.placeholder(tf.float32, [None, 10 * len(CHARS) + 1]) #7 changed to 10

    digits_loss, presence_loss, loss = get_loss(y, y_)
    train_step = tf.train.AdamOptimizer(learn_rate).minimize(loss)

    best = tf.argmax(tf.reshape(y[:, 1:], [-1, 10, len(CHARS)]), 2) # 7 changed to 10
    correct = tf.argmax(tf.reshape(y_[:, 1:], [-1, 10, len(CHARS)]), 2) #7 changed to 10

    if initial_weights is not None:
        assert len(params) == len(initial_weights)
        assign_ops = [w.assign(v) for w, v in zip(params, initial_weights)]

    init = tf.initialize_all_variables()

    def vec_to_plate(v):
        return "".join(CHARS[i] for i in v)

    def do_report():
        r = sess.run([best,
                      correct,
                      tf.greater(y[:, 0], 0),
                      y_[:, 0],
                      digits_loss,
                      presence_loss,
                      loss],
                     feed_dict={x: test_xs, y_: test_ys})
        num_correct = numpy.sum(
                        numpy.logical_or(
                            numpy.all(r[0] == r[1], axis=1),
                            numpy.logical_and(r[2] < 0.5,
                                              r[3] < 0.5)))
        r_short = (r[0][:190], r[1][:190], r[2][:190], r[3][:190])
        for b, c, pb, pc in zip(*r_short):
            #print "{} {} <-> {} {}".format(vec_to_plate(c), pc,
                                           #vec_to_plate(b), float(pb)) # print command needs to be changed according to python3
                print ("{} {} <-> {} {}".format(vec_to_plate(c), pc,
                                           vec_to_plate(b), float(pb)))
        num_p_correct = numpy.sum(r[2] == r[3])

        print ("B{:3d} {:2.02f}% {:02.02f}% loss: {} "
               "(digits: {}, presence: {}) |{}|".format(
            batch_idx,
            100. * num_correct / (len(r[0])),
            100. * num_p_correct / len(r[2]),
            r[6],
            r[4],
            r[5],
            "".join("X "[numpy.array_equal(b, c) or (not pb and not pc)]
                                           for b, c, pb, pc in zip(*r_short))))

    def do_batch():
        sess.run(train_step,
                 feed_dict={x: batch_xs, y_: batch_ys})
        if batch_idx % report_steps == 0:
            do_report()

    gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.95)
    with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:
        sess.run(init)
        if initial_weights is not None:
            sess.run(assign_ops)

        test_xs, test_ys = unzip(list(read_data("test/*.png"))[:50])

        try:
            last_batch_idx = 0
            last_batch_time = time.time()
            batch_iter = enumerate(read_batches(batch_size))
            for batch_idx, (batch_xs, batch_ys) in batch_iter:
                do_batch()
                if batch_idx % report_steps == 0:
                    batch_time = time.time()
                    if last_batch_idx != batch_idx:
                        print ("time for 60 batches {}".format(
                            60 * (last_batch_time - batch_time) /
                                            (last_batch_idx - batch_idx)))
                        last_batch_idx = batch_idx
                        last_batch_time = batch_time

        except KeyboardInterrupt:
            last_weights = [p.eval() for p in params]
            numpy.savez("weights.npz", *last_weights)
            return last_weights


if __name__ == "__main__":
    if len(sys.argv) > 1:
        f = numpy.load(sys.argv[1])
        initial_weights = [f[n] for n in sorted(f.files,
                                                key=lambda s: int(s[4:]))]
    else:
        initial_weights = None

    train(learn_rate=0.001,
          report_steps=20,
          batch_size=50,
          initial_weights=initial_weights)

这是我得到的错误:

Traceback (most recent call last):
  File "train_1.py", line 286, in <module>
    initial_weights=initial_weights)
  File "train_1.py", line 259, in train
    do_batch()
  File "train_1.py", line 242, in do_batch
    feed_dict={x: batch_xs, y_: batch_ys})
  File "/usr/lib/python2.7/site-packages/tensorflow/python/client/session.py", line 929, in run
    run_metadata_ptr)
  File "/usr/lib/python2.7/site-packages/tensorflow/python/client/session.py", line 1128, in _run
    str(subfeed_t.get_shape())))
ValueError: Cannot feed value of shape (50, 807) for Tensor u'Placeholder_1:0', which has shape '(?, 621)'

1 个答案:

答案 0 :(得分:0)

根据错误消息,问题在于您正在为占位符y_提供不同形状的值。您输入的占位符y_的形状为(batch_size, 621),但是要填充的batch_ys的形状为(batch_size, 807)

在您的实现中,batch_ys是由matricule函数的generate_code_train变量生成的。因此,您必须生成matricule且没有空格,因为您假设车牌的长度为10。

因此,只需在matricule函数中删除generate_code_train的空格。

def generate_code_train():
    #matricule =  "{}{} {}{} {}{} {}{}{}{}".format(
    matricule =  "{}{}{}{}{}{}{}{}{}{}".format(
        random.choice(common.DIGITS_0),
        random.choice(common.DIGITS),
        random.choice(common.DIGITS),
        random.choice(common.DIGITS),
        random.choice(common.DIGITS_E1),
        random.choice(common.BARRE),
        random.choice(common.LETTERS),
        random.choice(common.BARRE),
        random.choice(common.DIGITS_0),
        random.choice(common.DIGITS_E1))

    #matricule = matricule.decode("utf-8")

    return matricule

通过修改以上内容,您可以执行train_1.py,但
如果您使用原始的common.pygen.pymodel.py,请同时确认以下内容。

  • 用您的值替换LETTERS中的CHARScommon.py
  • 修改w_fc2的{​​{1}},b_fc2w_conv2的形状(即用10代替7)