In [1]:
from captcha.image import ImageCaptcha
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import random

number = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
ALPHABET = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
char_set = "".join(number + alphabet + ALPHABET)
char_set = "".join(number)


# 图像大小  
height = 60  
width = 160  
captcha_size = 4
n_class = len(char_set)

In [2]:
# 随机生成长度为4的字符串
def random_captcha_text(char_set = char_set, captcha_size = captcha_size):
    captcha_text = []
    for _ in range(captcha_size):
        c = random.choice(char_set)
        captcha_text.append(c)
    captcha_text = ''.join(captcha_text)
    return captcha_text

In [3]:
# 生成图片和label
def gen_captcha_text_and_image():
    image = ImageCaptcha()
    captcha_text = random_captcha_text()
    captcha = image.generate(captcha_text)
    captcha_image = Image.open(captcha)
    captcha_image = np.array(captcha_image)
    return captcha_text, captcha_image

In [4]:
text, image = gen_captcha_text_and_image()
plt.title(text)
plt.imshow(image)
plt.show()



In [5]:
# 生成一个训练batch  
def get_next_batch(batch_size=128):  
    # 创建2个空数组, 用来存放一个批次的数据
    batch_x = np.zeros([batch_size, height, width, 3])  
    batch_y = np.zeros([batch_size, captcha_size * n_class])  
   
    # 有时生成图像大小不是(60, 160, 3)  
    def wrap_gen_captcha_text_and_image():  
        while True:  
            text, image = gen_captcha_text_and_image()  
            if image.shape == (60, 160, 3):  
                return text, image  
   
    for i in range(batch_size):  
        text, image = wrap_gen_captcha_text_and_image()  
        
        batch_x[i,:] = image 
        # one-hot编码label
        for j, ch in enumerate(text):
            batch_y[i][:] = 0
            batch_y[i][j * n_class + char_set.find(ch)] = 1
            
    return batch_x, batch_y

In [6]:
get_next_batch(batch_size=4)


Out[6]:
(array([[[[ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          ..., 
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.]],
 
         [[ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          ..., 
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.]],
 
         [[ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          ..., 
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.]],
 
         ..., 
         [[ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          ..., 
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.]],
 
         [[ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          ..., 
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.]],
 
         [[ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          ..., 
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.],
          [ 240.,  238.,  243.]]],
 
 
        [[[ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          ..., 
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.]],
 
         [[ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          ..., 
          [ 169.,  217.,  170.],
          [ 221.,  238.,  223.],
          [ 252.,  251.,  255.]],
 
         [[ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          ..., 
          [ 148.,  209.,  148.],
          [ 169.,  217.,  170.],
          [ 252.,  251.,  255.]],
 
         ..., 
         [[ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          ..., 
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.]],
 
         [[ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          ..., 
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.]],
 
         [[ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          ..., 
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.],
          [ 252.,  251.,  255.]]],
 
 
        [[[ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          ..., 
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.]],
 
         [[ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          ..., 
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.]],
 
         [[ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          ..., 
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.]],
 
         ..., 
         [[ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          ..., 
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.]],
 
         [[ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          ..., 
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.]],
 
         [[ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          ..., 
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.],
          [ 249.,  242.,  249.]]],
 
 
        [[[ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          ..., 
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.]],
 
         [[ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          ..., 
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.]],
 
         [[ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          ..., 
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.]],
 
         ..., 
         [[ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          ..., 
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.]],
 
         [[ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          ..., 
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.]],
 
         [[ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          ..., 
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.],
          [ 252.,  246.,  254.]]]]),
 array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,
          0.],
        [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,
          0.],
        [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          1.],
        [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
          0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,
          0.]]))

In [7]:
from keras.models import *
from keras.layers import *
import numpy as np
import keras

def VGG16():
    input_tensor = Input((height, width, 3))
    x = input_tensor
    x = Conv2D(64, (3, 3), activation='relu', padding='SAME')(x)
    x = Conv2D(64, (3, 3), activation='relu', padding='SAME')(x)
    x = MaxPooling2D((2, 2), padding='SAME')(x)
    x = Dropout(0.5)(x)

    x = Conv2D(128, (3, 3), activation='relu', padding='SAME')(x)
    x = Conv2D(128, (3, 3), activation='relu', padding='SAME')(x)
    x = MaxPooling2D((2, 2), padding='SAME')(x)
    x = Dropout(0.5)(x)

    x = Conv2D(256, (3, 3), activation='relu', padding='SAME')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='SAME')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='SAME')(x)
    x = MaxPooling2D((2, 2), padding='SAME')(x)
    x = Dropout(0.5)(x)

    x = Conv2D(512, (3, 3), activation='relu', padding='SAME')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='SAME')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='SAME')(x)
    x = MaxPooling2D((2, 2), padding='SAME')(x)
    x = Dropout(0.5)(x)

    x = Conv2D(512, (3, 3), activation='relu', padding='SAME')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='SAME')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='SAME')(x)
    x = MaxPooling2D((2, 2), padding='SAME')(x)
    x = Dropout(0.5)(x)

    x = Flatten()(x)
    x = Dense(4096, activation='relu')(x)
    x = Dense(4096, activation='relu')(x)
    x = [Dense(n_class, activation='softmax', name='c%d'%(i+1))(x) for i in range(4)]
    model = Model(inputs=input_tensor, outputs=x)
    return model


model = VGG16()
model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])


Using TensorFlow backend.

In [8]:
import IPython.display
from keras.utils import plot_model

plot_model(model, show_shapes=True)

# 上面PIL库里面也有一个Image函数, 小心使用错误
IPython.display.Image('model.png')


Out[8]:

In [9]:
model.fit_generator(get_next_batch(32), 
                    samples_per_epoch=51200, 
                    nb_epoch=5, 
                    nb_worker=2, pickle_safe=True, 
                    validation_data=get_next_batch(32), nb_val_samples=1280)


/Users/hjl/anaconda/lib/python2.7/site-packages/ipykernel_launcher.py:5: UserWarning: The semantics of the Keras 2 argument `steps_per_epoch` is not the same as the Keras 1 argument `samples_per_epoch`. `steps_per_epoch` is the number of batches to draw from the generator at each epoch. Basically steps_per_epoch = samples_per_epoch/batch_size. Similarly `nb_val_samples`->`validation_steps` and `val_samples`->`steps` arguments have changed. Update your method calls accordingly.
  """
/Users/hjl/anaconda/lib/python2.7/site-packages/ipykernel_launcher.py:5: UserWarning: Update your `fit_generator` call to the Keras 2 API: `fit_generator((array([[[..., use_multiprocessing=True, workers=2, validation_data=(array([[[..., steps_per_epoch=51200, epochs=5, validation_steps=1280)`
  """
/Users/hjl/anaconda/lib/python2.7/site-packages/keras/engine/training.py:2023: UserWarning: Using a generator with `use_multiprocessing=True` and multiple workers may duplicate your data. Please consider using the`keras.utils.Sequence class.
  UserWarning('Using a generator with `use_multiprocessing=True`'
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-9-99a5fa4c48fd> in <module>()
      3                     nb_epoch=5,
      4                     nb_worker=2, pickle_safe=True,
----> 5                     validation_data=get_next_batch(32), nb_val_samples=1280)

/Users/hjl/anaconda/lib/python2.7/site-packages/keras/legacy/interfaces.pyc in wrapper(*args, **kwargs)
     85                 warnings.warn('Update your `' + object_name +
     86                               '` call to the Keras 2 API: ' + signature, stacklevel=2)
---> 87             return func(*args, **kwargs)
     88         wrapper._original_function = func
     89         return wrapper

/Users/hjl/anaconda/lib/python2.7/site-packages/keras/engine/training.pyc in fit_generator(self, generator, steps_per_epoch, epochs, verbose, callbacks, validation_data, validation_steps, class_weight, max_queue_size, workers, use_multiprocessing, shuffle, initial_epoch)
   2084                                  str(validation_data))
   2085             val_x, val_y, val_sample_weights = self._standardize_user_data(
-> 2086                 val_x, val_y, val_sample_weight)
   2087             val_data = val_x + val_y + val_sample_weights
   2088             if self.uses_learning_phase and not isinstance(K.learning_phase(), int):

/Users/hjl/anaconda/lib/python2.7/site-packages/keras/engine/training.pyc in _standardize_user_data(self, x, y, sample_weight, class_weight, check_batch_axis, batch_size)
   1416                                     output_shapes,
   1417                                     check_batch_axis=False,
-> 1418                                     exception_prefix='target')
   1419         sample_weights = _standardize_sample_weights(sample_weight,
   1420                                                      self._feed_output_names)

/Users/hjl/anaconda/lib/python2.7/site-packages/keras/engine/training.pyc in _standardize_input_data(data, names, shapes, check_batch_axis, exception_prefix)
    118                              exception_prefix +
    119                              ' arrays, but only received one array. '
--> 120                              'Found: array with shape ' + str(data.shape))
    121         arrays = [data]
    122 

ValueError: The model expects 4 target arrays, but only received one array. Found: array with shape (32, 40)

In [ ]:


In [ ]: