用于实现用python和django编写的图像分类的Keras UI

2019-06-24 09:49:06 浏览数 (1)

KerasUI是一种可视化工具,可以在图像分类中轻松训练模型,并允许将模型作为服务使用,只需调用API。

https://github.com/zeppaman/KerasUI

主要特点:

  • 用oauth2验证
  • 允许完整的模型定制
  • 可以上传尚未训练的模型并通过API消费
  • 测试表格和视觉检查网络如何工作
  • 批量上传训练集

用法

  • 运行standalone.bat或sh standalone.bat(这将安装需求应用迁移并运行服务器,相同的脚本适用于UNIX和Windows)
  • 使用创建管理员用户 python manage.py createsuperuser
  • 导航到http://127.0.0.1:8000/

这需要python 3 ,如果安装了多个版本,请根据(即pip3)更改脚本。

如何管理数据集

Keras UI允许将数据集项(图像)上载到Web应用程序中。您可以逐个执行此操作,也可以一次性添加包含许多图像的zip文件。它管理多个数据集,因此您可以将事物分开。加载图像后,可以单击“训练”按钮并运行训练过程。这将训练您定义的模型,而无需您进行任何交互。你将获得训练结果,如果你很挑剔,你可以转到日志文件,看看系统输出了什么

如何使用Web UI进行测试

为避免失眠,提供了一个简单的表格,可以上传图像并获得结果。

如何使用API UI或邮递员来测试API

在Web UI中看到的所有内容都可以使用API进行复制。

API使用情况

此应用程序使用oauth2来验证请求,因此需要的第一步是获取令牌。这是密码流的一个简单示例。请记住必须启用该应用程序(首次运行时不会默认创建)。

代码语言:javascript复制
Assuming
client hUiSQJcR9ZrmWSecwh1gloi7pqGTOclss4GwIt1o
secret ZuuLK21sQ2uZxk8dVG7k6pO474FBlM6DEQs7FQvDh28gdLtbCDJwFFi0YlTlLsbz9ddjUa7Lun6ifYwkfwyGMD95WsCuzibFWIMpsZHMA039RIv1mOsYUO5nK5ZVv1hB
 
POST to http://127.0.0.1:8000/o/token/
 
Headers:
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
 
Body:
grant_type:password
username:admin
password:admin2019!

回应是

代码语言:javascript复制
{
    "access_token": "h6WeZwYwqahFDqGDRr6mcToyAm3Eae",
    "expires_in": 36000,
    "token_type": "Bearer",
    "scope": "read write",
    "refresh_token": "eg97atDWMfqC1lYKW81XCvltj0sism"
}

获取预测的API可以在json post或form post中使用。在json post中,图像以base64字符串形式发送。这种使用服务的双重方式非常有用,因为可以将其链接到表单或直接与wget或curl工具一起使用,也可以在应用程序中使用它。

代码语言:javascript复制
POST http://127.0.0.1:8000/api/test/
 
Headers:
Content-Type:application/json
Authorization:Bearer <token>
 
Body
{
    "image":"<base 64 image",
    "dataset":1
}

响应

代码语言:javascript复制
{
    "result": "<LABEL PREDICTED>"
}

教程

该项目是Codeproject上图像分类上下文的一部分。这里是技术部分的演练,解释它是如何构建的以及它是如何工作的。

项目堆栈:

  • python
  • django框架
  • keras,tensorflow,numpy
  • sqlite(或您喜欢的其他数据库)

使用的工具:

  • Visual Studio代码
  • 邮差
  • 一个Web浏览器

项目设置

该项目基于Django,因此首先要做的是使用CLI创建一个Django项目。这需要从pip安装Django。

代码语言:javascript复制
django-admin startproject kerasui ' create the project

此命令将生成以下结构:

代码语言:javascript复制
kerasui/
    manage.py
    kerasui/
        __init__.py
        settings.py
        urls.py
        wsgi.py

这些文件是:

  • 外部kerasui / root目录只是项目的容器。内部mysite /目录是项目的实际Python包。它的名称是需要用来导入其中任何内容的Python包名称(例如mysite.urls)。
  • manage.py:一个命令行实用程序,允许以各种方式与此Django项目进行交互。可以在jango-admin和manage.py中阅读有关manage.py的所有详细信息。
  • __init__.py:一个空文件,告诉Python该目录应该被视为Python包。如果是Python初学者,请阅读官方Python文档中有关包的更多信息。
  • kerasui / settings.py:此Django项目的设置/配置。Django设置将告诉有关设置如何工作的所有信息。
  • kerasui / urls.py:此Django项目的URL声明; Django支持的站点的“目录”。可以在URL调度程序中阅读有关URL的更多信息。
  • kerasui / wsgi.py:与WSGI兼容的Web服务器的入口点,用于为项目提供服务。有关更多详细信息,请参阅如何使用WSGI进行部署。

运行

要检查是否一切正常,只需使用内置服务器运行django

代码语言:javascript复制
python manage.py runserver

也可以使用setup visual studio代码来运行django /

这是django配置:

代码语言:javascript复制
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Django",
            "type": "python",
            "request": "launch",
            "program": "${workspaceFolder}\kerasui\manage.py",
            "args": [
                "runserver",
                "--noreload",
                "--nothreading"
            ],
            "django": true
        }
    ]
}

设置配置

这里配置的基本部分告诉:

  • 使用oauth 2和会话认证使:常规Web用户登录并使用网站和休息沙箱,API用户获取令牌并查询API服务
  • 使用SQLite(可以更改为移动到任何其他数据库)
  • 添加所有Django模块(以及两个自定义:管理UI和API)
  • 启用cors
代码语言:javascript复制
INSTALLED_APPS = [
    'python_field',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'oauth2_provider',
    'corsheaders',
    'rest_framework',  
    'management',
    'api',
]
 
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
   # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'corsheaders.middleware.CorsMiddleware',
]
 
ROOT_URLCONF = 'kerasui.urls'
 
 
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
  
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 10,
}
 
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

第一次运行

Django使用迁移系统从您定义的模型生成迁移文件。要应用迁移,只需运行migrate命令(makemigration即可从模型创建迁移文件)。

用户数据库开始为空,因此需要创建admin用户才能登录。这是通过createsuperadmin命令完成的

代码语言:javascript复制
python manage.py migrate
python manage.py createsuperuser
adminadmin2019!

它是如何构建的

该应用程序分为3个模块:

  • 管理部分: Web UI,模块和所有核心内容
  • 后台工作者:是一个可以在后台执行的Django命令,用于根据数据集训练模型
  • API:此部分公开API以从外部与应用程序交互。例如,这允许从第三方应用程序向数据集添加项目。此外,最常见的用法是发送图像并获得预测结果

管理

在Django上创建一个应用程序:

代码语言:javascript复制
python manage.py startapp management

这将创建主文件。在这个模块中,使用的最多是模型和模型表示:

  • module.py:这里是所有具有现场规格的型号。通过这样的类定义,所有都被设置为对实体具有可用的CRUD
  • admin.py:此图层描述了如何使用表单显示和编辑数据。

数据模型非常简单。假设只想为每个数据集训练一个模型

  • DataSet:它包含模型,模型设置和数据集的名称。
  • DataSetItem:它包含数据集项,因此每行一个图像附加标签。

这里只是一个模型和模型表示的示例:

代码语言:javascript复制
#from admin.py
class DataSetForm( forms.ModelForm ): 
 
 
    process =forms.CharField( widget=forms.Textarea(attrs={'rows':40, 'cols':115}), initial=settings.PROCESS_TEMPLATE )
    model_labels =forms.CharField(initial="[]")
    class Meta:
        model = DataSet
        fields = ['name', 'process','epochs','batchSize','verbose','model_labels','model']
        widgets = {
          'process': forms.Textarea(attrs={'rows':20, 'cols':200}),
          }
    
def train(modeladmin, request, queryset):
       for dataset in queryset:
        DataSetAdmin.train_async(dataset.id)
 
class DataSetAdmin(admin.ModelAdmin):
    list_display = ('name','epochs','batchSize','verbose','progress')
    inlines = [
      #  DataSetItemInline,
    ]
    form=DataSetForm
    actions = [train]
    change_list_template = "dataset_changelist.html"
 
 
    @staticmethod
    def train(datasetid):
        call_command('train',datasetid)
    @staticmethod
    def train_async(datasetid):
        t = threading.Thread(target=DataSetAdmin.train, args=(datasetid,))
        t.setDaemon(True)
        t.start()
 
 
admin.site.register(DataSet,DataSetAdmin)
 
#from model.py
 
class DataSet(models.Model):
    name= models.CharField(max_length=200)
    process = models.CharField(max_length=5000, default=settings.PROCESS_TEMPLATE)
    model = models.ImageField(upload_to=path_model_name,max_length=300,db_column='modelPath',blank=True, null=True)
    #weights = models.ImageField(upload_to=path_model_name,max_length=300,db_column='weightPath',blank=True, null=True)
    batchSize = models.IntegerField(validators=[MaxValueValidator(100), MinValueValidator(1)],default=10)
    epochs = models.IntegerField(validators=[MaxValueValidator(100), MinValueValidator(1)],default=10)
    verbose = models.BooleanField(default=True)
    progress = models.FloatField(default=0)    
    model_labels= models.CharField(max_length=200)
    def __str__(self):
        return self.name

Django采用代码优先方法,因此需要运行python manage.py makemigrations以生成将应用于数据库的迁移文件。

代码语言:javascript复制
python manage.py makemigrations

背景工作者

要创建后台工作程序,需要一个模块来托管它,使用了管理模块。在其中需要创建一个management文件夹。其上的每个文件都可以python manage.py commandname通过API 运行或通过API 运行。

在例子中,通过常规的Django动作在后台进程中启动命令

这是相关部分:

代码语言:javascript复制
class DataSetAdmin(admin.ModelAdmin):
   
    actions = [train]
 
 
    # ....
    
    @staticmethod
    def train(datasetid):
        call_command('train',datasetid)
    @staticmethod
    def train_async(datasetid):
        t = threading.Thread(target=DataSetAdmin.train, args=(datasetid,))
        t.setDaemon(True)
        t.start()

API

API是在一个单独的应用程序中创建的

代码语言:javascript复制
python manage.py startapp API

基本上所有CRUD模型都可以通过API公开,但是需要指定如何序列化它

代码语言:javascript复制
class DataSetItemSerializer(serializers.HyperlinkedModelSerializer):
    image = Base64ImageField()
    dataset=   serializers.PrimaryKeyRelatedField(many=False, read_only=True)
    class Meta:
        model = DataSetItem
 
        # Fields to expose via API
        fields = ('label', 'image', 'dataset')
 
 
class DataSetSerializer(serializers.HyperlinkedModelSerializer):  
   
    class Meta:
        model = DataSet
        fields = ('name', 'process')

还需要创建ViewSet模型和数据表示之间的映射:

代码语言:javascript复制
class DataSetItemViewSet(viewsets.ModelViewSet):
   
    queryset = DataSetItem.objects.all()
    serializer_class = DataSetItemSerializer
 
class DataSetViewSet(viewsets.ModelViewSet):
   
    queryset = DataSet.objects.all()
    serializer_class = DataSetSerializer

最后需要定义所有路由并将viwset映射到url。这足以将模型用作api

代码语言:javascript复制
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'datasetitem', views.DataSetItemViewSet)
router.register(r'dataset', views.DataSetViewSet)
router.register(r'test', views.TestItemViewSet, basename='test')
 
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
 
urlpatterns  = staticfiles_urlpatterns()

训练

算法非常简单:

  1. 从数据集中获取所有图像
  2. 将它们标准化并添加到带标签的列表中
  3. 创建模型在数据集模型中的指定方式
  4. 训练它

这是查询数据集项和加载图像的代码段:

代码语言:javascript复制
def load_data(self, datasetid):
        self.stdout.write("loading images")
        train_data = []
        
        images = DataSetItem.objects.filter(dataset=datasetid)
        labels = [x['label'] for x in  DataSetItem.objects.values('label').distinct()]
      
        for image in images:
            self.stdout.write("Loading {0}".format(image.image))
            image_path = image.image.path
            if "DS_Store" not in image_path:           
                index=[x for x in range(len(labels)) if labels[x]==image.label]
                label = to_categorical([index,],len(labels))
                
                img = Image.open(image_path)
                img = img.convert('L')
                img = img.resize((self.IMAGE_SIZE, self.IMAGE_SIZE), Image.ANTIALIAS)
                train_data.append([np.array(img), np.array(label[0])])
            
        return train_data

看一眼:

代码语言:javascript复制
labels = [x['label'] for x in  DataSetItem.objects.values('label').distinct()]
label = to_categorical([index,],len(labels))

这为所有标签分配了一个顺序,即["CAT","DOGS"]然后to_categorical将位置索引转换为单热表示。用简单的话说,这使得CAT = [1,0]和DOG = [0,1]

训练模型

代码语言:javascript复制
   model=Sequential()
   exec(dataset.process)
   model.add(Dense(len(labels), activation = 'softmax'))
   model.fit(training_images, training_labels, batch_size=dataset.batchSize, epochs=dataset.epochs, verbose=dataset.verbose)

请注意,dataset.process是在Web管理员中输入的python模型定义,可以根据需要进行调整。最后一层添加到用户回调之外,以确保与数组大小匹配。

拟合方法只是使用所有数据运行训练(。

最后存储训练有素的模型:

代码语言:javascript复制
datasetToSave=DataSet.objects.get(pk=datasetid)
datasetToSave.progress=100
datasetToSave.model_labels=json.dumps(labels)
temp_file_name=str(uuid.uuid4()) '.h5'
model.save(temp_file_name)
datasetToSave.model.save('weights.h5',File(open(temp_file_name, mode='rb')))
os.remove(temp_file_name)
datasetToSave.save()

请注意还保存标签顺序beacuse必须与模型相同才能匹配one-hot约定。

预测

有一种常见的方法,给定样本和数据集,检索模型,加载模型并进行预测。这是一段代码:

代码语言:javascript复制
def predict(image_path,datasetid):
        
            dataset=DataSet.objects.get(pk=datasetid)
            modelpath=dataset.model.path
            model=load_model(modelpath)
            labels=json.loads(dataset.model_labels)
            
            img = Image.open(image_path)
            img = img.convert('L')
            img = img.resize((256, 256), Image.ANTIALIAS)
 
            result= model.predict(np.array(img).reshape(-1,256,256, 1))
            max=result[0]
            idx=0
            for i in range(1,len(result)):
                if max<result[i]:
                    max=result[i]
                    idx=i
 
 
            return labels[idx]

使用模型加载模型load_model(modelpath),标签来自数据库。模型预测输出作为值列表,选择较高的索引并用于检索在训练时分配给网络输出的正确标签。

0 人点赞