2018-07-26 17:30:25 u013569304 阅读数 3061
  • 云从科技:详解CNN-pFSMN模型以及在语音识别中的应用

    近日,云从科技在语音识别技术上取得重大突破,在全球最大的开源语音识别数据集Librispeech上刷新了世界纪录,错词率(Worderrorrate,WER)降到了2.97%,将Librispeech的WER指标提升了25%,大幅刷新原先记录。本视频课程讲解了:大规模词汇连续语音识别,LVCSR前沿与最新进展,和CNN-pFSMN声学模型。

    965 人正在学习 去看看 CSDN讲师

CNN看的差不多了,直接上代码吧,CNN的介绍什么的就不发了,参考这篇博客,讲的很清楚。有一点需要明确的是卷积核应该是[宽,高,通道数量,filter数量]四维。可以看着下面这张非常有名的图理解一下:

下面是代码,还是用MNIST数据集,数据集的下载和说明可以翻我以前的博客,不再一直说了,两个卷积层,一个全连接层。其他的练习都在https://github.com/IMLHF/tensorflow_practice上。

# -*- coding: utf-8 -*-
# github :https://github.com/IMLHF/tensorflow_practice
# -*- coding: utf-8 -*-
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

__mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

__learning_rate=0.0001
__training_epochs = 600
__batch_size = 100  # 每批训练数据的大小
__display_step = 10  # 每隔__display_step批次显示一次进度

'''
tf.nn.conv2d 卷积函数
参数 input 输入图像              四维,shape如[batch, in_height, in_width, in_channels]
参数 filter 卷积核               四维,shape如[filter_height, filter_width, in_channels, out_channels]
参数 strides 卷积核移动步长       列表,卷积时在图像每一维的步长
参数 padding 边缘处理方式       SAME和VALID,SAME就是可以在外围补0再卷积,VALID会检查步长是否合理,不能补0
返回 Tensor
'''
def conv2d(__x_input, __conv_kernel):
  return tf.nn.conv2d(__x_input, __conv_kernel, strides=[1, 1, 1, 1], padding='SAME')


'''
tf.nn.max_pool 池化函数
参数 value 输入图像               四维,shape如[batch_num, height, width, channels]
参数 ksize 池化窗口大小            列表[batch, height, width, channels]
参数 strides 池化窗口移动步长       列表[batch, height, width, channels],
一般不对batch和图像通道数进行池化,所以ksize和strides的batch个channels都是1
参数 padding 边缘处理方式      SAME和VALID,SAME就是可以在外围补0再卷积,VALID会检查步长是否合理,不能补0
返回 Tensor
'''
def max_pooling_2x2(__max_pooling_target):
  return tf.nn.max_pool(__max_pooling_target, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')



#定义权值和偏置
__weights = {
    # 截断正态分布获取随机值
    # [batch, in_height, in_width, in_channels]
    # 5x5x1x32,卷积核的视野大小是5x5,输入图像通道为1,该层卷积核32个filter
    '__w_conv1': tf.Variable(tf.truncated_normal(shape=[5, 5, 1, 32], stddev=0.1)),
    # [filter_height, filter_width, in_channels, out_channels]
    # 5x5x32x64,同样是卷积核的视野大小是5x5,因为上一层使用了32个filter,
    # 所以上层生成结果的通道为32,该层卷积核有64个filter
    '__w_conv2': tf.Variable(tf.truncated_normal(shape=[5, 5, 32, 64], stddev=0.1)),
    '__w_fc1': tf.Variable(tf.truncated_normal(shape=[7 * 7 * 64, 1024], stddev=0.1)),
    '__w_fc2': tf.Variable(tf.truncated_normal(shape=[1024, 10], stddev=0.1)),
}
__biases={
    '__b_conv1': tf.Variable(tf.constant(0.1, shape=[32])),
    '__b_conv2': tf.Variable(tf.constant(0.1, shape=[64])),
    '__b_fc1': tf.Variable(tf.constant(0.1, shape=[1024])),
    '__b_fc2': tf.Variable(tf.constant(0.1, shape=[10]))
}

# region 创建CNN结构
def conv_net(__x_t,__keep_probability_t):
  #shape,-1表示有此维度,但是数值不定
  __x_image = tf.reshape(__x_t, [-1, 28, 28, 1])
  __h_conv1 = tf.nn.relu(conv2d(__x_image, __weights['__w_conv1']) + __biases['__b_conv1'])
  __h_pool1 = max_pooling_2x2(__h_conv1)
  __h_conv2 = tf.nn.relu(conv2d(__h_pool1, __weights['__w_conv2']) + __biases['__b_conv2'])
  __h_pool2 = max_pooling_2x2(__h_conv2)
  __h_pool2_flat = tf.reshape(__h_pool2, [-1, 7 * 7 * 64])
  __h_fc1 = tf.nn.relu(tf.matmul(__h_pool2_flat, __weights['__w_fc1']) + __biases['__b_fc1'])

  # tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None, name=None)
  # 防止过拟合   在对输入的数据进行一定的取舍,从而降低过拟合
  # 参数 x 输入数据
  # 参数 keep_prob 保留率             对输入数据保留完整返回的概率
  # 返回 Tensor
  __h_fc1_drop = tf.nn.dropout(__h_fc1, __keep_probability_t)

  # tf.nn.softmax(logits, dim=-1, name=None): SoftMax函数
  # 参数 logits 输入            一般输入是logit函数的结果
  # 参数 dim 卷积核             指定是第几个维度,默认是-1,表示最后一个维度
  # 返回 Tensor
  __y_conv_logits = tf.matmul(__h_fc1_drop, __weights['__w_fc2']) + __biases['__b_fc2']
  return __y_conv_logits
#endregion


__X_input = tf.placeholder(tf.float32, [None, 784])
__Y_true = tf.placeholder(tf.float32, [None, 10])
__keep_probability = tf.placeholder(tf.float32)

__logits=conv_net(__X_input,__keep_probability)
__out_softmax=tf.nn.softmax(__logits)
# __loss_cross_entropy = tf.reduce_mean(
#     -tf.reduce_sum(__Y_true * tf.log(__out_softmax), axis=1))
__loss_cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(logits=__logits, labels=__Y_true))

__train_op = tf.train.AdamOptimizer(__learning_rate).minimize(__loss_cross_entropy)

__accuracy = tf.reduce_mean(
    tf.cast(tf.equal(tf.argmax(__out_softmax, 1), tf.argmax(__Y_true, 1)), tf.float32))

init=tf.global_variables_initializer()

with tf.Session() as __session_t:
  __session_t.run(init)
  for i in range(__training_epochs):
    # Datasets.train.next_batch 获取批量处样本
    # 返回 [image,label]
    __x_batch,__y_batch = __mnist.train.next_batch(__batch_size)

    if i % __display_step == 0:
      __train_accuracy = __session_t.run(
          __accuracy,
          feed_dict={__X_input: __x_batch,
                     __Y_true: __y_batch,
                     __keep_probability: 1.0})
      print("step %d, training accuracy %g" % (i, __train_accuracy))

    __train_op.run(feed_dict={__X_input: __x_batch, __Y_true: __y_batch, __keep_probability: 0.5})

  print("test accuracy %g" % __session_t.run(
      __accuracy,
      feed_dict={__X_input: __mnist.test.images,
                 __Y_true: __mnist.test.labels,
                 __keep_probability: 1.0}))

 

2019-04-09 16:31:59 bayhax 阅读数 184
  • 云从科技:详解CNN-pFSMN模型以及在语音识别中的应用

    近日,云从科技在语音识别技术上取得重大突破,在全球最大的开源语音识别数据集Librispeech上刷新了世界纪录,错词率(Worderrorrate,WER)降到了2.97%,将Librispeech的WER指标提升了25%,大幅刷新原先记录。本视频课程讲解了:大规模词汇连续语音识别,LVCSR前沿与最新进展,和CNN-pFSMN声学模型。

    965 人正在学习 去看看 CSDN讲师

写作目的

最近在做自己的毕业设计,打算做的是基于tensorflow利用CNN算法进行识别。于是查找资料之后,就做了花朵识别分类程序,在github上找到了一个可以用的程序,于是copy下来,自己进行改动来实现自己想要的功能。然后在指导老师的建议下,增加了语音识别指定的图片这个模块。在增加这个模块的过程中,遇到了很多问题,所以特此记录下来,方便日后查看改进,也希望能够给看到此文章的同学一些帮助。
github链接: [https://github.com/bayhax/FlowerRecognize]
我所用的编程环境: win7+spyder3.6+tensorflow1.13.1+百度AipSpeech

python语音模块

语音转文字处理模块

目前有很多语音处理模块,比如 PyPI中
apiai
google-cloud-speech
pocketsphinx
SpeechRecognition
waston-developer-cloud
完全可以自行去百度或者Google,或者去官网看文档,都是很不错的选择。
由于我使用的是SpeechRecognition,所以就记录一些它的使用过程。
安装
pip install SpeechRecognition
如果有在线网络下载慢等问题可以去官网下载whl文件,进入whl文件目录进行安装
官网链接[https://pypi.org/project/SpeechRecognition/#files]
安装完之后再python交互界面测试一下

import speech_recognition as sr     
sr.__version__

显示出版本信息之后就证明安装成功了。
使用
下面是我使用的时候的一段代码

import speech_recognition as sr
import logging
logging.basicConfig(level=logging.DEBUG)

while True:
    #speech_recognition的核心是识别器类
    r = sr.Recognizer()
    #麦克风
    mic = sr.Microphone()
    logging.info('录音中')
    with mic as source:
        #去噪声
        r.adjust_for_ambient_noise(source)
        audio = r.listen(source)
    
    logging.info('录音结束,识别中.....')
    test = r.recognize_google(audio,language='cmn-Hans-CN',show_all=True)
    #print(test[0])
    #这里注意这个recognize_google返回的test,如果是空文件,返回的是一个列表
    #如果不是空文件,返回的是一个包含列表的字典
    if isinstance(test,list):
        print("空")
    else:
        print(test['alternative'][0]['transcript'])
        print(type(test['alternative'][0]['transcript']))
    #print(type(test))
    logging.info('end')

文字转语音处理模块

文字转语音模块也有很多,比如Google,百度,讯飞等等,我个人使用的是百度的AipSpeech,所以说说它的使用方法,也蛮方便的。
安装
pip install AipSpeech
然后去百度AI开放平台,点击控制台,创建自己的应用,获取自己的ID,KEY等。
使用

# -*- coding: utf-8 -*-
#百度AI平台提供的语音库文件,playsound播放音频
from aip import AipSpeech
import shutil
#百度AI平台的ID秘钥等,APPID AK SK """
APP_ID = '你自己的ID'
API_KEY = '你自己的KEY'
SECRET_KEY = '你自己的秘钥'
#定义自己的初始化AipSpeech对象
myspeech = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
num = 0
#要转换的文字信息
result  = myspeech.synthesis('二营长,把老子的意大利炮拿来', 'zh', 1, {
    'spd':3,'pit':9,'vol': 6,'per':4
})
#如果识别正确,则返回语音的二进文件写入自己定义的audio文件中,错误则返回dict
#这里注意一下,with open打开写入文件用相对路劲有时候会出错,用绝对路径会相对好一些。
if not isinstance(result, dict):
    with open(r'.\test\audio'+str(num)+'.mp3', 'wb') as f:
        f.write(result)
 #复制文件
shutil.copy(r'.\test\audio'+str(num)+'.mp3', r'.\testcopy\audio'+str(num)+'.mp3')

播放音频文件模块

播放音频文件可以用pygame,mp3play,playsound等等,我用的是playsound,但是我的渣渣电脑可能有问题,也有可能是我什么地方做错了,我用哪种播放方式都无法关闭播放的文件,导致我无法删除或者重新写入文件,所以只好复制音频文件,播放副本,每次生成新的名字的音频文件。然后运行完再手动删除副本文件。如果是某一种格式的音频无法播放或者有问题,可以试着用ffmpeg将文件转换格式。同理去它的官网下载轮子或者pip安装适合自己的版本都是可以的。当然ffmpeg需要pydub。安装pydub等这些python的库,用pip,conda或者下载whl文件,都是还算好解决的。下面给大家一段mp3格式转到wav格式的代码。其他转换同理。

from pydub import AudioSegment
#要转换的文件的路径
filepath=".\\test\\audio0.mp3"
def trans_mp3_to_wav(filepath):
    song = AudioSegment.from_mp3(filepath)
    print("转换....")
    #转换完的文件存储路径及格式
    song.export(".\\testcopy\\test.wav", format="wav")

if __name__ == "__main__":
    trans_mp3_to_wav(filepath)

在github上查看playsound的文件,发现好像没有关闭音频的方式
下面是playsound的python文件

  def winCommand(*command):
        buf = c_buffer(255)
        command = ' '.join(command).encode(getfilesystemencoding())
        errorCode = int(windll.winmm.mciSendStringA(command, buf, 254, 0))
        if errorCode:
            errorBuffer = c_buffer(255)
            windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
            exceptionMessage = ('\n    Error ' + str(errorCode) + ' for command:'
                                '\n        ' + command.decode() +
                                '\n    ' + errorBuffer.value.decode())
            raise PlaysoundException(exceptionMessage)
        return buf.value

    alias = 'playsound_' + str(random())
    winCommand('open "' + sound + '" alias', alias)
    winCommand('set', alias, 'time format milliseconds')
    durationInMS = winCommand('status', alias, 'length')
    winCommand('play', alias, 'from 0 to', durationInMS.decode())

    if block:
        sleep(float(durationInMS) / 1000.0)

回到正题
安装
pip install playsound
使用

from playsound import playsound
playsound("你自己的音频文件的路径")

总结

增加这个语音识别模块的这几天,当明明感觉程序没问题却就是报错,然后模块用起来不尽人意的时候,还是着实让人烦恼的,不过最后还是初成模型,实现了自己想要的功能还是不错滴,期待日后找出不能关闭音频文件的原因,然后改进。完整的花朵分类的程序(三个功能:选择本地图片进行识别,拍照识别,语音识别),见文章的最前面github链接。

2016-07-07 08:46:56 guchuanhang 阅读数 6926
  • 云从科技:详解CNN-pFSMN模型以及在语音识别中的应用

    近日,云从科技在语音识别技术上取得重大突破,在全球最大的开源语音识别数据集Librispeech上刷新了世界纪录,错词率(Worderrorrate,WER)降到了2.97%,将Librispeech的WER指标提升了25%,大幅刷新原先记录。本视频课程讲解了:大规模词汇连续语音识别,LVCSR前沿与最新进展,和CNN-pFSMN声学模型。

    965 人正在学习 去看看 CSDN讲师

高德地图官方导航部分Demo使用android sdk 24编译,执行会崩溃。经过和高德工程师的交涉得知,地图中使用了科大讯飞的语音模块,崩溃的就是语音部分。探究一下科大讯飞语音识别,在此记录一下成长点滴!
这里使用的是科大讯飞

科大讯飞API提供的功能

  • 语音合成

    将一段文字转换为成语音,可根据需要合成出不同音色、语速和语调的声音,让机器像人一样开口说话。

  • 语音听写

    将一段语音转换成文本,把语音中包含文字信息提取出来,并可以优先识别用户手机特有的联系人和个性化数据。

  • 语法识别

    判断用户所说的内容是否与预定义的语法相符合, 主要用于识别用户是否下达某项指令,使用语法识别前,需要先定义语法。

  • 语义理解

    在语音听写基础上,分析理解用户的说话意图,返回结构化的指令信息。开发者可在语义开放平台定义专属的问答格式。

  • 语音评测

    通过智能语音技术自动对发音水平进行评价,给出用户综合得分和发音信息。

  • 声纹密码

    据语音波形反映说话人生理和行为特征的语音参数,自动识别说话人身份,声纹识别所提供的安全性可与其他生物识别技术(指纹、掌形和虹膜)相媲美。

  • 人脸识别

    基于人的脸部特征信息进行身份识别的一种生物识别技术,可以自动在图像中检测和跟踪人脸,进而对检测到的人脸进行检测和验证。系统同时支持人脸关键点检出、视频流人脸检测等功能,识别率高达 99%。

由于时间和能力限制,这里仅仅对语音听写&&语音合成中的云服务部分进行简单探究

环境搭建

讯飞官网,申请一个开发者账号,创建一个应用,下载相应的sdk,添加相关的jar和so文件。
1.在Application中完成讯飞模块的初始化

 @Override
    public void onCreate() {
        super.onCreate();
        // 将“12345678”替换成您申请的 APPID
// 请勿在“ =” 与 appid 之间添加任务空字符或者转义符
SpeechUtility.createUtility(context, SpeechConstant.APPID +"=12345678");
        SpeechUtility.createUtility(this, SpeechConstant.APPID +"=12345678");
    }

2.添加相应的权限

  <!--连接网络权限,用于执行云端语音能力 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!--读取网络信息状态 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--获取当前wifi状态 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!--允许程序改变网络连接状态 -->
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <!--读取手机信息权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!--读取联系人权限,上传联系人需要用到此权限 -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <!--外存储写权限, 构建语法需要用到此权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!--外存储读权限,构建语法需要用到此权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!--配置权限,用来记录应用配置信息 -->
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

    <!--摄相头权限, 拍照需要用到 -->
    <uses-permission android:name="android.permission.CAMERA" />

语音合成

就是将文本读出来
使用的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
    <!--activity_text2speech.xml-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingLeft="10dp"
    android:paddingRight="10dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="讯飞合成示例"
        android:textSize="30sp" />

    <EditText
        android:id="@+id/tts_text"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="top|left"
        android:text="科大讯飞作为中国最大的智能语音技术提供商,在智能语音技术领域有着长期的研究积累,并在中文语音合成、语音识别、
    口语评测等多项技术上拥有国际领先的成果。科大讯飞是我国唯一以语音技术为产业化方向的“国家863计划成果产业化基地”…"
        android:textSize="20sp" />


    <Button
        android:id="@+id/tts_play"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始合成"
        android:textSize="20sp" />

</LinearLayout>

java代码如下:

package com.iflytek.voicedemo;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.EditText;
import android.widget.Toast;

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SynthesizerListener;

public class Text2SpeechActivity extends Activity implements OnClickListener {
    // 语音合成对象
    private SpeechSynthesizer mTts;
    private Toast mToast;

    @SuppressLint("ShowToast")
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_text2speech);

        findViewById(R.id.tts_play).setOnClickListener(this);
        // 初始化合成对象
        mTts = SpeechSynthesizer.createSynthesizer(this, null);

        mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
        applyPermission();
    }

    //获取权限,将语音保存到sd卡
    private void applyPermission() {
        ActivityCompat.requestPermissions(this, new String[]{
                Manifest.permission.READ_EXTERNAL_STORAGE
        }, 12);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            // 开始合成
            // 收到onCompleted 回调时,合成结束、生成合成音频
            // 合成的音频格式:只支持pcm格式
            case R.id.tts_play: {
                String text = ((EditText) findViewById(R.id.tts_text)).getText().toString();
                // 设置参数
                setParam();
                int code = mTts.startSpeaking(text, mTtsListener);
//          /** 
//           * 只保存音频不进行播放接口,调用此接口请注释startSpeaking接口
//           * text:要合成的文本,uri:需要保存的音频全路径,listener:回调接口
//          */
//          String path = Environment.getExternalStorageDirectory()+"/tts.pcm";
//          int code = mTts.synthesizeToUri(text, path, mTtsListener);
                if (code != ErrorCode.SUCCESS) {
                    showTip("语音合成失败,错误码: " + code);
                }
            }
            break;
        }

    }

    /**
     * 合成回调监听。
     */
    private SynthesizerListener mTtsListener = new SynthesizerListener() {

        @Override
        public void onSpeakBegin() {
            showTip("开始播放");
        }

        @Override
        public void onSpeakPaused() {
            showTip("暂停播放");
        }

        @Override
        public void onSpeakResumed() {
            showTip("继续播放");
        }

        @Override
        public void onBufferProgress(int percent, int beginPos, int endPos,
                                     String info) {
            // 合成进度
        }

        @Override
        public void onSpeakProgress(int percent, int beginPos, int endPos) {
            // 播放进度
        }

        @Override
        public void onCompleted(SpeechError error) {
            if (error == null) {
                showTip("播放完成");
            } else if (error != null) {
                showTip(error.getPlainDescription(true));
            }
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因
            // 若使用本地能力,会话id为null
 // if (SpeechEvent.EVENT_SESSION_ID == eventType) {
//      String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
            //      Log.d(TAG, "session id =" + sid);
            //  }
        }
    };

    private void showTip(final String str) {
        mToast.setText(str);
        mToast.show();
    }

    /**
     * 参数设置
     *
     * @return
     */
    private void setParam() {
        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);
        // 根据合成引擎设置相应参数
        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        // 设置在线合成发音人
        mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");
        //设置合成语速
        mTts.setParameter(SpeechConstant.SPEED,
                "50");
        //设置合成音调
        mTts.setParameter(SpeechConstant.PITCH, "50");
        //设置合成音量
        mTts.setParameter(SpeechConstant.VOLUME,
                "50");
        //设置播放器音频流类型
        mTts.setParameter(SpeechConstant.STREAM_TYPE,
                "3");
        // 设置播放合成音频打断音乐播放,默认为true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");

        // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        // 注:AUDIO_FORMAT参数语记需要更新版本才能生效
        mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/tts.wav");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mTts.stopSpeaking();
        // 退出时释放连接
        mTts.destroy();
    }

}

使用官方封装的UI,进行语音听写

为了便于开发者调用,讯飞封装了一套用于语音输入的UI。在使用之前需要将官方Demo中的assets目录下的iflytek放到你的项目的assets目录下。其内容如下:

这里写图片描述
展示界面的布局文件

<?xml version="1.0" encoding="utf-8"?>
    <!--activity_speech2text_ui.xml-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingLeft="10dp"
    android:paddingRight="10dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="讯飞听写示例"
        android:textSize="30sp" />

    <EditText
        android:id="@+id/iat_text"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="top|left"
        android:paddingBottom="20dp"
        android:textSize="20sp" />

    <Button
        android:id="@+id/iat_recognize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始"
        android:textSize="20sp" />

</LinearLayout>

java代码:

package com.iflytek.voicedemo;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.EditText;
import android.widget.Toast;

import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;
import com.iflytek.speech.util.JsonParser;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.LinkedHashMap;

public class Speech2TextUIActivity extends Activity implements OnClickListener {
    private static String TAG = Speech2TextUIActivity.class.getSimpleName();
    // 语音听写UI
    private RecognizerDialog mIatDialog;
    // 用HashMap存储听写结果
    private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();

    private EditText mResultText;
    private Toast mToast;

    @SuppressLint("ShowToast")
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_speech2text_ui);

        findViewById(R.id.iat_recognize).setOnClickListener(this);
        // 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer
        // 使用UI听写功能,放置布局文件和图片资源
        //使用云服务InitListener参数写成null
        mIatDialog = new RecognizerDialog(this, null);

        mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
        mResultText = ((EditText) findViewById(R.id.iat_text));
        applyPermission();
    }

    private void applyPermission() {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 12);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            // 开始听写
            // 如何判断一次听写结束:OnResult isLast=true 或者 onError
            case R.id.iat_recognize:
                mResultText.setText(null);// 清空显示内容
                mIatResults.clear();
                // 显示听写对话框
                mIatDialog.setListener(mRecognizerDialogListener);
                mIatDialog.show();
                showTip("请开始说话…");
                break;
            default:
                break;
        }
    }


    private void printResult(RecognizerResult results) {
        String text = JsonParser.parseIatResult(results.getResultString());

        String sn = null;
        // 读取json结果中的sn字段
        try {
            JSONObject resultJson = new JSONObject(results.getResultString());
            sn = resultJson.optString("sn");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        mIatResults.put(sn, text);

        StringBuffer resultBuffer = new StringBuffer();
        for (String key : mIatResults.keySet()) {
            resultBuffer.append(mIatResults.get(key));
        }

        mResultText.setText(resultBuffer.toString());
        mResultText.setSelection(mResultText.length());
    }

    /**
     * 听写UI监听器
     */
    private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
        public void onResult(RecognizerResult results, boolean isLast) {
            printResult(results);
        }

        /**
         * 识别回调错误.
         */
        public void onError(SpeechError error) {
            showTip(error.getPlainDescription(true));
        }

    };


    private void showTip(final String str) {
        mToast.setText(str);
        mToast.show();
    }

}

解释服务器返回数据,用到的工具类

package com.iflytek.speech.util;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;

import android.util.Log;

/**
 * Json结果解析类
 */
public class JsonParser {

    public static String parseIatResult(String json) {
        StringBuffer ret = new StringBuffer();
        try {
            JSONObject joResult = new JSONObject(json);

            JSONArray words = joResult.getJSONArray("ws");
            for (int i = 0; i < words.length(); i++) {
                // 转写结果词,默认使用第一个结果
                JSONArray items = words.getJSONObject(i).getJSONArray("cw");
                JSONObject obj = items.getJSONObject(0);
                ret.append(obj.getString("w"));
//              如果需要多候选结果,解析数组其他字段
//              for(int j = 0; j < items.length(); j++)
//              {
//                  JSONObject obj = items.getJSONObject(j);
//                  ret.append(obj.getString("w"));
//              }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return ret.toString();
    }

    public static String parseGrammarResult(String json) {
        StringBuffer ret = new StringBuffer();
        try {
            JSONTokener tokener = new JSONTokener(json);
            JSONObject joResult = new JSONObject(tokener);

            JSONArray words = joResult.getJSONArray("ws");
            for (int i = 0; i < words.length(); i++) {
                JSONArray items = words.getJSONObject(i).getJSONArray("cw");
                for(int j = 0; j < items.length(); j++)
                {
                    JSONObject obj = items.getJSONObject(j);
                    if(obj.getString("w").contains("nomatch"))
                    {
                        ret.append("没有匹配结果.");
                        return ret.toString();
                    }
                    ret.append("【结果】" + obj.getString("w"));
                    ret.append("【置信度】" + obj.getInt("sc"));
                    ret.append("\n");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            ret.append("没有匹配结果.");
        } 
        return ret.toString();
    }

    public static String parseLocalGrammarResult(String json) {
        StringBuffer ret = new StringBuffer();
        try {
            JSONTokener tokener = new JSONTokener(json);
            JSONObject joResult = new JSONObject(tokener);

            JSONArray words = joResult.getJSONArray("ws");
            for (int i = 0; i < words.length(); i++) {
                JSONArray items = words.getJSONObject(i).getJSONArray("cw");
                for(int j = 0; j < items.length(); j++)
                {
                    JSONObject obj = items.getJSONObject(j);
                    if(obj.getString("w").contains("nomatch"))
                    {
                        ret.append("没有匹配结果.");
                        return ret.toString();
                    }
                    ret.append("【结果】" + obj.getString("w"));
                    ret.append("\n");
                }
            }
            ret.append("【置信度】" + joResult.optInt("sc"));

        } catch (Exception e) {
            e.printStackTrace();
            ret.append("没有匹配结果.");
        } 
        return ret.toString();
    }
}

这里写图片描述
官方定制的UI还是挺漂亮的!

不使用官方UI控件进行语音听写

使用到的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
    <!--activity_speech2text.xml-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingLeft="10dp"
    android:paddingRight="10dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="讯飞听写示例"
        android:textSize="30sp" />

    <EditText
        android:id="@+id/iat_text"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="top|left"
        android:paddingBottom="20dp"
        android:textSize="20sp" />


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="2dp"
        android:layout_marginTop="10dp"
        android:gravity="center_horizontal"
        android:orientation="horizontal">

        <Button
            android:id="@+id/iat_recognize"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="开始"
            android:textSize="20sp" />

        <Button
            android:id="@+id/iat_stop"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="停止"
            android:textSize="20sp" />

        <Button
            android:id="@+id/iat_cancel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="取消"
            android:textSize="20sp" />
    </LinearLayout>

</LinearLayout>

java代码:

package com.iflytek.voicedemo;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.EditText;
import android.widget.Toast;

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.speech.util.JsonParser;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.LinkedHashMap;

public class Speech2TextActivity extends Activity implements OnClickListener {
    private static String TAG = Speech2TextActivity.class.getSimpleName();
    // 语音听写对象
    private SpeechRecognizer mIat;
    // 用HashMap存储听写结果
    private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();

    private EditText mResultText;
    private Toast mToast;

    @SuppressLint("ShowToast")
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_speech2text);

        findViewById(R.id.iat_recognize).setOnClickListener(Speech2TextActivity.this);
        findViewById(R.id.iat_stop).setOnClickListener(Speech2TextActivity.this);
        findViewById(R.id.iat_cancel).setOnClickListener(Speech2TextActivity.this);
        mIat = SpeechRecognizer.createRecognizer(this, null);

        mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
        mResultText = ((EditText) findViewById(R.id.iat_text));
        applyPermission();
    }

    private void applyPermission() {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 12);

    }

    int ret = 0; // 函数调用返回值

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            // 开始听写
            // 如何判断一次听写结束:OnResult isLast=true 或者 onError
            case R.id.iat_recognize:
                mResultText.setText(null);// 清空显示内容
                mIatResults.clear();
                // 设置参数
                setParam();
                ret = mIat.startListening(mRecognizerListener);
                if (ret != ErrorCode.SUCCESS) {
                    showTip("听写失败,错误码:" + ret);
                }
                break;
            case R.id.iat_stop:
                mIat.stopListening();
                showTip("停止听写");
                break;
            case R.id.iat_cancel:
                mIat.cancel();
                showTip("取消听写");
                break;
            default:
                break;
        }
    }


    /**
     * 听写监听器。
     */
    private RecognizerListener mRecognizerListener = new RecognizerListener() {

        @Override
        public void onBeginOfSpeech() {
            // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入
            showTip("开始说话");
        }

        @Override
        public void onError(SpeechError error) {
            // Tips:
            // 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。
            // 如果使用本地功能(语记)需要提示用户开启语记的录音权限。
            showTip(error.getPlainDescription(true));
        }

        @Override
        public void onEndOfSpeech() {
            // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入
            showTip("结束说话");
        }

        @Override
        public void onResult(RecognizerResult results, boolean isLast) {
            Log.d(TAG, results.getResultString());
            printResult(results);
        }

        @Override
        public void onVolumeChanged(int volume, byte[] data) {
            showTip("当前正在说话,音量大小:" + volume);
            Log.d(TAG, "返回音频数据:" + data.length);
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因
            // 若使用本地能力,会话id为null
            //  if (SpeechEvent.EVENT_SESSION_ID == eventType) {
            //      String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
            //      Log.d(TAG, "session id =" + sid);
            //  }
        }
    };

    private void printResult(RecognizerResult results) {
        String text = JsonParser.parseIatResult(results.getResultString());

        String sn = null;
        // 读取json结果中的sn字段
        try {
            JSONObject resultJson = new JSONObject(results.getResultString());
            sn = resultJson.optString("sn");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        mIatResults.put(sn, text);

        StringBuffer resultBuffer = new StringBuffer();
        for (String key : mIatResults.keySet()) {
            resultBuffer.append(mIatResults.get(key));
        }

        mResultText.setText(resultBuffer.toString());
        mResultText.setSelection(mResultText.length());
    }


    private void showTip(final String str) {
        mToast.setText(str);
        mToast.show();
    }

    /**
     * 参数设置
     */
    public void setParam() {
        // 清空参数
        mIat.setParameter(SpeechConstant.PARAMS, null);
        // 设置听写引擎
        mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        // 设置返回结果格式
        mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");

        // 设置语言
        mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        // 设置语言区域
        mIat.setParameter(SpeechConstant.ACCENT, "mandarin");

        // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
        mIat.setParameter(SpeechConstant.VAD_BOS, "4000");

        // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
        mIat.setParameter(SpeechConstant.VAD_EOS, "1000");

        // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
        mIat.setParameter(SpeechConstant.ASR_PTT, "1");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 退出时释放连接
        mIat.cancel();
        mIat.destroy();
    }

}
2018-03-15 13:12:26 weixin_41376374 阅读数 63
  • 云从科技:详解CNN-pFSMN模型以及在语音识别中的应用

    近日,云从科技在语音识别技术上取得重大突破,在全球最大的开源语音识别数据集Librispeech上刷新了世界纪录,错词率(Worderrorrate,WER)降到了2.97%,将Librispeech的WER指标提升了25%,大幅刷新原先记录。本视频课程讲解了:大规模词汇连续语音识别,LVCSR前沿与最新进展,和CNN-pFSMN声学模型。

    965 人正在学习 去看看 CSDN讲师


本人还有两个月的时间找工作,想要在这有限的时间里掌握语音识别的一些重要,常用的经典算法

要学的范畴有

HMM,BP神经网络,GMM,DNN,RNN,CNN,LTSM,RNN-LTSM,DNN-HMM,CNN-HMM,GMM-HMM

任务量繁重,但是不需要对每一个掌握的很精细

不用知道每一个数学公式如何推导,程序如何编写

我要知道的是每一个的工作原理,工作机制,它能应用的范围,同时用自己已有的语音材料对其进行训练验证即可

希望这段时间是能享受于其中的,不顾虑太多,也不欺骗自己


2019-07-10 17:03:27 weixin_43772246 阅读数 4
  • 云从科技:详解CNN-pFSMN模型以及在语音识别中的应用

    近日,云从科技在语音识别技术上取得重大突破,在全球最大的开源语音识别数据集Librispeech上刷新了世界纪录,错词率(Worderrorrate,WER)降到了2.97%,将Librispeech的WER指标提升了25%,大幅刷新原先记录。本视频课程讲解了:大规模词汇连续语音识别,LVCSR前沿与最新进展,和CNN-pFSMN声学模型。

    965 人正在学习 去看看 CSDN讲师

2019.7.10
今天的任务是看懂CNN,并自己搭建一个可以跑起来的CNN

什么是CNN

CNN是Convolutional Neural Networks的缩写,简而言之就是一种神经网络,只是其中进行的运算是卷积运算。具体的算法我在这里也就不说了,其他文章中也有相应的图文说明,大家自行查看。

CNN的写法与用法

以下是我如何从0写出一个能跑起来的程序:
1、首先,我使用的pycharm来运行的,其中我们需要的库文件是这样:

import numpy as np
import struct
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.datasets import mnist
import matplotlib.pyplot as plt
from keras.layers import Flatten
from keras.layers.convolutional import Convolution2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils

2、CNN又几个部分组成:Convolution层,MaxPooling层,Dropout层,Flatten层,Dense层,我来一个一个介绍
(1)指明结构
首先使用model=Sequential()指明我们使用的结构是Sequential(层次结构),在这个结构下,我们可以通过,add的函数来轻松的添加我们所需要的层
(2)Convolution层
这一层主要是来做卷积运算的,在add这一层的时候,使用
model.add(Convolution2D(20,(5,5),padding='same',input_shape=(1,28,28),activation='relu'))
来实现,其中20的意思是有20个卷积核,这个可以随意更改(5,5)指的是每个卷积核大小是5×5的,padding一定要注意,这个需要你设定是’same’还是’valid’,如果选valid,意思是说经过卷积后的图片大小会改变,如果选same则卷积后的图片大小他会给你添一些0呀什么的保证这个卷积后的图片大小不改变,我的经验是无脑same,这样会避免一些报错.之后input_shape的意思是输入图片的大小和维度,像我这个就是一个28×28的图片,然后activation的意思是选择激活函数,分类问题无脑relu就OK。
(3)MaxPooling层
这一层主要是做池化的,池化就是把一个框里的特征提一些出来,池化有两种一种是平均池化一种是最大值池化,我用的是最大值池化,就是把框里的特征的最大值提出来model.add(MaxPooling2D(pool_size=(2,2),padding='same'))
上面的代码就是把池化的框设为2×2,然后也变为了same,这样省的出错。
(4)Dropout层

model.add(Dropout(0.2))

上面的代码意思是说添加一个Dropout层,防止过拟合,0.2为选择遗忘率,把一些权重忘记,这样不会过拟合,有时候这样还会使结果变好呢。
(5)Flatten层
无脑model.add(Flatten())就行。
(6)Dense层

model.add(Dense(128,activation='relu'))
model.add(Dense(50,activation='relu'))
model.add(Dense(num_classes,activation='softmax'))
model.summary()
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
return model

128和50指的是神经元的数量,目前我还不知道他们这些数字有什么关系,反正就这么写吧,就这样,一个神经网络模型就已经搭好了,理论上讲,使用model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=128, verbose=2)往里输入特征矩阵,就可以输出一些东西了,这个就叫做训练。

本文涉及的最终代码

num_classes = y_test.shape[1]

# define a simple CNN model
def simple_cnn():
    model=Sequential()
    model.add(Convolution2D(20,(5,5),padding='same',input_shape=(1,28,28),activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2),padding='same'))
    model.add(Convolution2D(50,(5,5),padding='same',input_shape=(1,28,28),activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2),padding='same'))
    model.add(Dropout(0.2))
    model.add(Flatten())
    model.add(Dense(128,activation='relu'))
    model.add(Dense(50,activation='relu'))
    model.add(Dense(num_classes,activation='softmax'))
    model.summary()
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model
# build the model
model = simple_cnn()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=128, verbose=2)

# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("CNN Error: %.2f%%" % (100-scores[1]*100))

就可以输出错误率了。

能跑的程序

我下载了一个mnist的手写数据集,解压后放在跟python文件一个目录下就可以用了

import numpy as np
import struct
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.datasets import mnist
import matplotlib.pyplot as plt
from keras.layers import Flatten
from keras.layers.convolutional import Convolution2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils


# 训练集文件
train_images_idx3_ubyte_file = 'D:/first_py/train-images.idx3-ubyte'
# 训练集标签文件
train_labels_idx1_ubyte_file = 'D:/first_py/train-labels.idx1-ubyte'
# 测试集文件
test_images_idx3_ubyte_file = 'D:/first_py/t10k-images.idx3-ubyte'
# 测试集标签文件
test_labels_idx1_ubyte_file = 'D:/first_py/t10k-labels.idx1-ubyte'


def decode_idx3_ubyte(idx3_ubyte_file):
    """
    解析idx3文件的通用函数
    :param idx3_ubyte_file: idx3文件路径
    :return: 数据集
    """
    # 读取二进制数据
    bin_data = open(idx3_ubyte_file, 'rb').read()

    # 解析文件头信息,依次为魔数、图片数量、每张图片高、每张图片宽
    offset = 0
    fmt_header = '>iiii' #因为数据结构中前4行的数据类型都是32位整型,所以采用i格式,但我们需要读取前4行数据,所以需要4个i。我们后面会看到标签集中,只使用2个ii。
    magic_number, num_images, num_rows, num_cols = struct.unpack_from(fmt_header, bin_data, offset)
    print('魔数:%d, 图片数量: %d张, 图片大小: %d*%d' % (magic_number, num_images, num_rows, num_cols))

    # 解析数据集
    image_size = num_rows * num_cols
    offset += struct.calcsize(fmt_header)  #获得数据在缓存中的指针位置,从前面介绍的数据结构可以看出,读取了前4行之后,指针位置(即偏移位置offset)指向0016。
    print(offset)
    fmt_image = '>' + str(image_size) + 'B'  #图像数据像素值的类型为unsigned char型,对应的format格式为B。这里还有加上图像大小784,是为了读取784个B格式数据,如果没有则只会读取一个值(即一副图像中的一个像素值)
    print(fmt_image,offset,struct.calcsize(fmt_image))
    images = np.empty((num_images, num_rows, num_cols))
    #plt.figure()
    for i in range(num_images):
        if (i + 1) % 10000 == 0:
            print('已解析 %d' % (i + 1) + '张')
            print(offset)
        images[i] = np.array(struct.unpack_from(fmt_image, bin_data, offset)).reshape((num_rows, num_cols))
        #print(images[i])
        offset += struct.calcsize(fmt_image)
#        plt.imshow(images[i],'gray')
#        plt.pause(0.00001)
#        plt.show()
    #plt.show()

    return images


def decode_idx1_ubyte(idx1_ubyte_file):
    """
    解析idx1文件的通用函数
    :param idx1_ubyte_file: idx1文件路径
    :return: 数据集
    """
    # 读取二进制数据
    bin_data = open(idx1_ubyte_file, 'rb').read()

    # 解析文件头信息,依次为魔数和标签数
    offset = 0
    fmt_header = '>ii'
    magic_number, num_images = struct.unpack_from(fmt_header, bin_data, offset)
    print('魔数:%d, 图片数量: %d张' % (magic_number, num_images))

    # 解析数据集
    offset += struct.calcsize(fmt_header)
    fmt_image = '>B'
    labels = np.empty(num_images)
    for i in range(num_images):
        if (i + 1) % 10000 == 0:
            print ('已解析 %d' % (i + 1) + '张')
        labels[i] = struct.unpack_from(fmt_image, bin_data, offset)[0]
        offset += struct.calcsize(fmt_image)
    return labels


def load_train_images(idx_ubyte_file=train_images_idx3_ubyte_file):
    """
    TRAINING SET IMAGE FILE (train-images-idx3-ubyte):
    [offset] [type]          [value]          [description]
    0000     32 bit integer  0x00000803(2051) magic number
    0004     32 bit integer  60000            number of images
    0008     32 bit integer  28               number of rows
    0012     32 bit integer  28               number of columns
    0016     unsigned byte   ??               pixel
    0017     unsigned byte   ??               pixel
    ........
    xxxx     unsigned byte   ??               pixel
    Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).

    :param idx_ubyte_file: idx文件路径
    :return: n*row*col维np.array对象,n为图片数量
    """
    return decode_idx3_ubyte(idx_ubyte_file)


def load_train_labels(idx_ubyte_file=train_labels_idx1_ubyte_file):
    """
    TRAINING SET LABEL FILE (train-labels-idx1-ubyte):
    [offset] [type]          [value]          [description]
    0000     32 bit integer  0x00000801(2049) magic number (MSB first)
    0004     32 bit integer  60000            number of items
    0008     unsigned byte   ??               label
    0009     unsigned byte   ??               label
    ........
    xxxx     unsigned byte   ??               label
    The labels values are 0 to 9.

    :param idx_ubyte_file: idx文件路径
    :return: n*1维np.array对象,n为图片数量
    """
    return decode_idx1_ubyte(idx_ubyte_file)


def load_test_images(idx_ubyte_file=test_images_idx3_ubyte_file):
    """
    TEST SET IMAGE FILE (t10k-images-idx3-ubyte):
    [offset] [type]          [value]          [description]
    0000     32 bit integer  0x00000803(2051) magic number
    0004     32 bit integer  10000            number of images
    0008     32 bit integer  28               number of rows
    0012     32 bit integer  28               number of columns
    0016     unsigned byte   ??               pixel
    0017     unsigned byte   ??               pixel
    ........
    xxxx     unsigned byte   ??               pixel
    Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).

    :param idx_ubyte_file: idx文件路径
    :return: n*row*col维np.array对象,n为图片数量
    """
    return decode_idx3_ubyte(idx_ubyte_file)


def load_test_labels(idx_ubyte_file=test_labels_idx1_ubyte_file):
    """
    TEST SET LABEL FILE (t10k-labels-idx1-ubyte):
    [offset] [type]          [value]          [description]
    0000     32 bit integer  0x00000801(2049) magic number (MSB first)
    0004     32 bit integer  10000            number of items
    0008     unsigned byte   ??               label
    0009     unsigned byte   ??               label
    ........
    xxxx     unsigned byte   ??               label
    The labels values are 0 to 9.

    :param idx_ubyte_file: idx文件路径
    :return: n*1维np.array对象,n为图片数量
    """
    return decode_idx1_ubyte(idx_ubyte_file)
seed = 7
np.random.seed(seed)
#加载数据
X_train = load_train_images()
y_train = load_train_labels()
X_test = load_test_images()
y_test = load_test_labels()
'''导入文件'''
# reshape to be [samples][channels][width][height]
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype('float32')
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype('float32')
#print(X_train.shape)
# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255

# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]

# define a simple CNN model
def simple_cnn():
    model=Sequential()
    model.add(Convolution2D(20,(5,5),padding='same',input_shape=(1,28,28),activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2),padding='same'))
    model.add(Convolution2D(50,(5,5),padding='same',input_shape=(1,28,28),activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2),padding='same'))
    model.add(Dropout(0.2))
    model.add(Flatten())
    model.add(Dense(128,activation='relu'))
    model.add(Dense(50,activation='relu'))
    model.add(Dense(num_classes,activation='softmax'))
    model.summary()
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model
# build the model
model = simple_cnn()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=128, verbose=2)

# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("CNN Error: %.2f%%" % (100-scores[1]*100))
没有更多推荐了,返回首页