<jupyter_start><jupyter_text>自製手寫繁體中文圖片測試    Step 0: 匯入套件<jupyter_code>from platform import python_version
import os
import shutil
import numpy as np
import pandas as pd
import PIL.Image
from matplotlib import pyplot as plt 
'''
繁體中文顯示設定
'''
from matplotlib.font_manager import FontProperties
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei'] 
plt.rcParams['axes.unicode_minus'] = False

import tensorflow as tf
from tensorflow.keras.preprocessing.image import load_img, ImageDataGenerator
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout  
from tensorflow.keras.optimizers import *

print( 'Python Version: ', python_version() )
print( 'TensorFlow Version: ', tf.__version__ )
print( 'Keras Version: ', tf.keras.__version__ )<jupyter_output>Python Version:  3.7.6
TensorFlow Version:  2.1.0
Keras Version:  2.2.4-tf<jupyter_text>Step 1: 訓練集與自製測試集路徑  自製繁中手寫測試集 :   利用小畫家自製繁體中文字   * 底圖大小: 50x50 像素   * 白底黑字    * 像素筆線條粗細: 1 像素   ![自製繁中手寫資料](https://raw.githubusercontent.com/AI-FREE-Team/Handwriting-Chinese-Characters-Recognition/master/img/HomeMade_Traditional_Chinese.png)將上述小畫家自製的繁中手寫文字，以 png 檔儲存，且放於以該字為名的資料夾中，其中，每個字專屬的資料夾皆存在於下面程式變數 TestingDataPath 設定的路徑中，如下圖所示:   ![自製繁中手寫資料集](https://raw.githubusercontent.com/AI-FREE-Team/Handwriting-Chinese-Characters-Recognition/master/img/HomeMade_Traditional_Chinese_Dataset.png)<jupyter_code>'''
RawDataPath: 繁中手寫資料集路徑
TraningDataPath: 訓練集路徑
TestingDataPath: 自製繁中手寫資料集路徑
'''
RawDataPath = 'D:/Traditional_Chinese_Data/'
TraningDataPath = 'D:/Traditional_Chinese_Training_Data/'
TestingDataPath = 'D:/Traditional_Chinese_Testing_Data/'

os.chdir( RawDataPath )
print( 'Current working directory:', os.getcwd() )<jupyter_output>Current working directory: D:\Traditional_Chinese_Data<jupyter_text>Step 2: 訓練集   從繁體中文手寫資料集中，選擇欲辨識的繁體中文字集，作為訓練集。<jupyter_code>SelectedWords = [ '人', '工', '智', '慧' ]

os.chdir( RawDataPath )
try: 
    os.mkdir( TraningDataPath ) 

except:
    shutil.rmtree( TraningDataPath )
    os.mkdir( TraningDataPath ) 

finally: 
    nonexistence = []
    for c in SelectedWords:
        try: 
            shutil.copytree( RawDataPath+'/'+c, TraningDataPath+'/'+c )
        except: 
            nonexistence.append( c )
            
    if len(nonexistence)>1: 
        print( f'There are {len(nonexistence)} characters that are not in dataset. \n{nonexistence}' )
    elif len(nonexistence)==1:
        print( f'There is {len(nonexistence)} character that is not in dataset. \n{nonexistence}' )
    else: print('')
def Loading_Image( image_path ):
    img = load_img( image_path )  
    img = tf.constant( np.array(img) )  
    return img

def Show( image, title=None ) :
    if len( image.shape )>3 :
        image = tf.squeeze( image, axis=0 )   

    plt.imshow( image )
    if title:
        plt.title( title )
        

img_list = []
for c in SelectedWords : 
    folder_path = TraningDataPath+'/'+c
    file_names = os.listdir( folder_path )
    for i in range(5) :
        img_list.append( folder_path+'/'+file_names[i] )

plt.gcf().set_size_inches( (12,12) ) 
for i in range(20):      
    plt.subplot(4,5,i+1)
    title = img_list[i].split('/')[-1].split('_')[-2]
    img = Loading_Image( img_list[i] )
    Show( img, title )<jupyter_output><empty_output><jupyter_text>Step 3: (超)參數<jupyter_code>Num_Classes = len(SelectedWords)
Image_Size = ( 50, 50 )
Epochs = 50
Batch_Size = 8<jupyter_output><empty_output><jupyter_text>Step 4: 資料擴增( Data Augmentation )   (4.1) 訓練集<jupyter_code>Train_Data_Genetor = ImageDataGenerator( rescale = 1./255, validation_split = 0.2,
                                         width_shift_range = 0.05,   
                                         height_shift_range = 0.05,
                                         zoom_range = 0.1,  
                                         horizontal_flip = False )
Train_Generator = Train_Data_Genetor.flow_from_directory( TraningDataPath ,
                                                          target_size = Image_Size,
                                                          batch_size = Batch_Size,
                                                          class_mode = 'categorical',
                                                          shuffle = True, 
                                                          subset = 'training' )
def Plot_Genetor( imgs, labels=[], grid=(1,10), size=(20,2) ):
    n = len( imgs )             
    plt.gcf().set_size_inches(size) 
    for i in range(n):           
        ax = plt.subplot( grid[0], grid[1], i+1 )   
        ax.imshow( imgs[i] )            
        if len(labels):
            ax.set_title( f'Label={labels[i]}' )   
        ax.set_xticks([]); ax.set_yticks([]) 
    plt.show()  

batch = 1
for data, label in Train_Generator:
    print( f'batch {batch}: \n shape of images: {data.shape} \n shape of labels: {label.shape}' )
    Plot_Genetor( data, label )
    batch += 1
    if batch > len(Train_Generator): 
        break

print( f'There are {len(Train_Generator)} batches.' )<jupyter_output>batch 1: 
 shape of images: (8, 50, 50, 3) 
 shape of labels: (8, 4)<jupyter_text>(4.2) 驗證集<jupyter_code>Val_Data_Genetor = ImageDataGenerator( rescale=1./255, validation_split = 0.2 )
Val_Generator = Train_Data_Genetor.flow_from_directory( TraningDataPath ,
                                                        target_size = Image_Size,
                                                        batch_size = Batch_Size,
                                                        class_mode = 'categorical',
                                                        shuffle = True, 
                                                        subset = 'validation' )<jupyter_output>Found 40 images belonging to 4 classes.<jupyter_text>Step 5: 建立及編譯模型<jupyter_code>CNN = Sequential( name = 'CNN_Model' )
CNN.add( Conv2D( 5, kernel_size = (2,2), padding = 'same', 
                 input_shape = (Image_Size[0],Image_Size[1],3), name = 'Convolution' ) )
CNN.add( MaxPooling2D( pool_size = (2,2), name = 'Pooling' ) )
CNN.add( Flatten( name = 'Flatten' ) )
CNN.add( Dropout( 0.5, name = 'Dropout_1' ) )
CNN.add( Dense( 512, activation = 'relu', name = 'Dense' ) )
CNN.add( Dropout( 0.5, name = 'Dropout_2' ) )
CNN.add( Dense( Num_Classes, activation = 'softmax', name = 'Softmax' ) )
CNN.summary()
CNN.compile( optimizer = Adam(),
             loss = 'categorical_crossentropy', 
             metrics = ['accuracy'] )<jupyter_output><empty_output><jupyter_text>Step 6: 訓練及儲存模型<jupyter_code>History = CNN.fit( Train_Generator,
                   steps_per_epoch = Train_Generator.samples//Batch_Size,
                   validation_data = Val_Generator,
                   validation_steps = Val_Generator.samples//Batch_Size,
                   epochs = Epochs )
Train_Accuracy = History.history['accuracy']
Val_Accuracy = History.history['val_accuracy']
Train_Loss = History.history['loss']
Val_Loss = History.history['val_loss']
epochs_range = range(Epochs)

plt.figure( figsize=(14,4) )
plt.subplot( 1,2,1 )
plt.plot( range( len(Train_Accuracy) ), Train_Accuracy, label='Train' ) 
plt.plot( range( len(Val_Accuracy) ), Val_Accuracy, label='Validation' ) 
plt.legend( loc='lower right' )
plt.title( 'Accuracy' )

plt.subplot( 1,2,2 )
plt.plot( range( len(Train_Loss) ), Train_Loss, label='Train' )
plt.plot( range( len(Val_Loss) ), Val_Loss, label='Validation' )
plt.legend( loc='upper right' )
plt.title( 'Loss')

plt.show()<jupyter_output><empty_output><jupyter_text>儲存模型<jupyter_code>os.chdir( TraningDataPath )
CNN.save( 'CNN_Model.h5' )<jupyter_output><empty_output><jupyter_text>Step 7: 自製繁中手寫測試集預測  (7.1) 建立自製測試集的生成器( Generator )及走訪器( Iterator )<jupyter_code>Test_Data_Genetor = ImageDataGenerator( rescale=1./255 )
Test_Generator = Test_Data_Genetor.flow_from_directory( TestingDataPath,
                                                        target_size = Image_Size,
                                                        shuffle = False,
                                                        class_mode = 'categorical' )
batch = 1
for data, label in Test_Generator:
    print( f'batch {batch}: \n shape of images: {data.shape} \n shape of labels: {label.shape}' )
    Plot_Genetor( data, label )
    batch += 1
    if batch > 1: 
        break<jupyter_output>batch 1: 
 shape of images: (8, 50, 50, 3) 
 shape of labels: (8, 4)<jupyter_text>(7.2) 載入模型且預測<jupyter_code>CNN = load_model( 'CNN_Model.h5' ) # Loading pretrained model
Predicts = CNN.predict( Test_Generator )<jupyter_output><empty_output><jupyter_text>(7.3) 檢視預測結果<jupyter_code>test_data, test_label = Test_Generator.next()

def Plot_Predict( img, labels=[], predicts=[], size=(20,2) ):             
    plt.gcf().set_size_inches(size)           
    ax = plt.subplot( )   
    ax.imshow( img )            
    ax.set_title( f'Predict={predicts.round(1)} \nLabel={labels}' )   
    ax.set_xticks([]); ax.set_yticks([]) 
    plt.show() 
    
for data, label, predict_label in zip(test_data,  test_label, Predicts):
    Plot_Predict( data, label, predict_label )<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11948449104412408, 'fraction_numerical': 0.0163826998689384, 'mean_word_length': 2.6598721023181455, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 48, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '386559', 'license': 'MIT', 'n_tokens_mistral': 3453, 'n_tokens_neox': 3318, 'n_words': 611, 'path': 'Traditional_Chinese_CNN_Model_local.ipynb', 'repo_name': 'esti20000425/Handwriting-Chinese-Characters-Recognition', 'size': '9156'}