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
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()
训练
算法非常简单:
- 从数据集中获取所有图像
- 将它们标准化并添加到带标签的列表中
- 创建模型在数据集模型中的指定方式
- 训练它
这是查询数据集项和加载图像的代码段:
代码语言: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),标签来自数据库。模型预测输出作为值列表,选择较高的索引并用于检索在训练时分配给网络输出的正确标签。