docker與tensorflow結(jié)合使用

個(gè)人博客:https://lightnine.github.io,歡迎大家交流

最近這段時(shí)間一直在學(xué)習(xí)docker的使用,以及如何在docker中使用tensorflow.今天就把在docker中如何使用tensorflow記錄一下.

docker安裝

我是把docker安裝在centos 7.4操作系統(tǒng)上面,在vmware中裝的centos,vmware中安裝centos很簡(jiǎn)單.具體的網(wǎng)絡(luò)配置可以參考vmware nat配置.docker安裝很簡(jiǎn)單,找到docker官網(wǎng),直接按照上面的步驟安裝即可.運(yùn)行docker version查看版本如下

image

因?yàn)閐ocker 采用的是客戶端/服務(wù)端的結(jié)構(gòu),所以這里可以看到client以及server,它們分別都有版本號(hào).

tensorflow

在docker中運(yùn)行tensorflow的第一步就是要找到自己需要的鏡像,我們可以去docker hub找到自己需要的tensorflow鏡像.tensorflow的鏡像主要分兩類,一種是在CPU上面跑的,還有一種是在GPU上面跑的,如果需要GPU的,那么還需要安裝nvidia-docker.這里我使用的是CPU版本的.當(dāng)然我們還需要選擇具體的tensorflow版本.這里我拉取的命令如下:


docker pull tensorflow/tensorflow:1.9.0-devel-py3

拉取成功之后,運(yùn)行docker images可以看到有tensorflow鏡像.

tensorflow在docker中使用


docker run -it -p 8888:8888 --name tf-1.9 tensorflow/tensorflow:1.9.0-devel-py3

運(yùn)行上面的命令,在容器中啟動(dòng)鏡像.-p表示指定端口映射,即將本機(jī)的8888端口映射到容器的8888端口.--name用來指定容器的名字為tf-1.9.因?yàn)檫@里采用的鏡像是devel模式的,所以默認(rèn)不啟動(dòng)jupyter.如果想使用默認(rèn)啟動(dòng)jupyter的鏡像,那么直接拉取不帶devel的鏡像就可以.即拉取最近的鏡像docker pull tensorflow/tensorflow

啟動(dòng)之后,我們就進(jìn)入了容器,ls / 查看容器根目錄內(nèi)容,可以看到有run_jupyter.sh文件.運(yùn)行此文件,即在根目錄下執(zhí)行./run_jupyter.sh --allow-root,--allow-root參數(shù)是因?yàn)閖upyter啟動(dòng)不推薦使用root,這里是主動(dòng)允許使用root.然后在瀏覽器中就可以訪問jupyter的內(nèi)容了.

image

創(chuàng)建自己的鏡像

上面僅僅是跑了一個(gè)什么都沒有的鏡像,如果我們需要在鏡像里面跑我們的深度學(xué)習(xí)程序怎么辦呢?這首先做的第一步就是要制作我們自己的鏡像.這里我們跑一個(gè)簡(jiǎn)單的mnist數(shù)據(jù)集,程序可以直接去tensorflow上面找一個(gè)例子程序.這里我的程序如下:


# Copyright 2015 The TensorFlow Authors. All Rights Reserved.

#

# Licensed under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance with the License.

# You may obtain a copy of the License at

#

#    http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

# ==============================================================================

"""Simple, end-to-end, LeNet-5-like convolutional MNIST model example.

This should achieve a test error of 0.7%. Please keep this model as simple and

linear as possible, it is meant as a tutorial for simple convolutional models.

Run with --self_test on the command line to execute a short self-test.

"""

from __future__ import absolute_import

from __future__ import division

from __future__ import print_function

import argparse

import gzip

import os

import sys

import time

import logging

import numpy

from six.moves import urllib

from six.moves import xrange  # pylint: disable=redefined-builtin

import tensorflow as tf

# CVDF mirror of http://yann.lecun.com/exdb/mnist/

# 如果WORK_DIRECTORY中沒有需要的數(shù)據(jù),則從此地址下載數(shù)據(jù)

SOURCE_URL = 'https://storage.googleapis.com/cvdf-datasets/mnist/'

# 訓(xùn)練數(shù)據(jù)位置

# WORK_DIRECTORY = 'data'

WORK_DIRECTORY = './MNIST-data'

IMAGE_SIZE = 28

NUM_CHANNELS = 1

PIXEL_DEPTH = 255

NUM_LABELS = 10

VALIDATION_SIZE = 5000  # Size of the validation set.

SEED = 66478  # Set to None for random seed.

BATCH_SIZE = 64

NUM_EPOCHS = 10

EVAL_BATCH_SIZE = 64

EVAL_FREQUENCY = 100  # Number of steps between evaluations.

FLAGS = None

# 打印信息設(shè)置

# logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',

#                    level=logging.DEBUG)

logging.basicConfig(level=logging.DEBUG,  # 控制臺(tái)打印的日志級(jí)別

                    filename='cnn_mnist.log',

                    filemode='a',  # 模式椭微,有w和a暇赤,w就是寫模式,每次都會(huì)重新寫日志薇芝,覆蓋之前的日志

                    # a是追加模式,默認(rèn)如果不寫的話,就是追加模式

                    format=

                    '%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'

                    # 日志格式

                    )

def data_type():

    """Return the type of the activations, weights, and placeholder variables."""

    if FLAGS.use_fp16:

        return tf.float16

    else:

        return tf.float32

def maybe_download(filename):

    """Download the data from Yann's website, unless it's already here."""

    if not tf.gfile.Exists(WORK_DIRECTORY):

        tf.gfile.MakeDirs(WORK_DIRECTORY)

    filepath = os.path.join(WORK_DIRECTORY, filename)

    if not tf.gfile.Exists(filepath):

        filepath, _ = urllib.request.urlretrieve(SOURCE_URL + filename, filepath)

        with tf.gfile.GFile(filepath) as f:

            size = f.size()

        print('Successfully downloaded', filename, size, 'bytes.')

    return filepath

def extract_data(filename, num_images):

    """Extract the images into a 4D tensor [image index, y, x, channels].

    Values are rescaled from [0, 255] down to [-0.5, 0.5].

    """

    logging.info('Extracting' + filename)

    print('Extracting', filename)

    with gzip.open(filename) as bytestream:

        bytestream.read(16)

        buf = bytestream.read(IMAGE_SIZE * IMAGE_SIZE * num_images * NUM_CHANNELS)

        data = numpy.frombuffer(buf, dtype=numpy.uint8).astype(numpy.float32)

        data = (data - (PIXEL_DEPTH / 2.0)) / PIXEL_DEPTH

        data = data.reshape(num_images, IMAGE_SIZE, IMAGE_SIZE, NUM_CHANNELS)

        return data

def extract_labels(filename, num_images):

    """Extract the labels into a vector of int64 label IDs."""

    logging.info('Extracting' + filename)

    print('Extracting', filename)

    with gzip.open(filename) as bytestream:

        bytestream.read(8)

        buf = bytestream.read(1 * num_images)

        labels = numpy.frombuffer(buf, dtype=numpy.uint8).astype(numpy.int64)

    return labels

def fake_data(num_images):

    """Generate a fake dataset that matches the dimensions of MNIST."""

    data = numpy.ndarray(

        shape=(num_images, IMAGE_SIZE, IMAGE_SIZE, NUM_CHANNELS),

        dtype=numpy.float32)

    labels = numpy.zeros(shape=(num_images,), dtype=numpy.int64)

    for image in xrange(num_images):

        label = image % 2

        data[image, :, :, 0] = label - 0.5

        labels[image] = label

    return data, labels

def error_rate(predictions, labels):

    """Return the error rate based on dense predictions and sparse labels."""

    return 100.0 - (

            100.0 *

            numpy.sum(numpy.argmax(predictions, 1) == labels) /

            predictions.shape[0])

def main(_):

    if FLAGS.self_test:

        logging.info('Running self-test.')

        print('Running self-test.')

        train_data, train_labels = fake_data(256)

        validation_data, validation_labels = fake_data(EVAL_BATCH_SIZE)

        test_data, test_labels = fake_data(EVAL_BATCH_SIZE)

        num_epochs = 1

    else:

        # Get the data.

        train_data_filename = maybe_download('train-images-idx3-ubyte.gz')

        train_labels_filename = maybe_download('train-labels-idx1-ubyte.gz')

        test_data_filename = maybe_download('t10k-images-idx3-ubyte.gz')

        test_labels_filename = maybe_download('t10k-labels-idx1-ubyte.gz')

        # Extract it into numpy arrays.

        train_data = extract_data(train_data_filename, 60000)

        train_labels = extract_labels(train_labels_filename, 60000)

        test_data = extract_data(test_data_filename, 10000)

        test_labels = extract_labels(test_labels_filename, 10000)

        # Generate a validation set.

        validation_data = train_data[:VALIDATION_SIZE, ...]

        validation_labels = train_labels[:VALIDATION_SIZE]

        train_data = train_data[VALIDATION_SIZE:, ...]

        train_labels = train_labels[VALIDATION_SIZE:]

        num_epochs = NUM_EPOCHS

    train_size = train_labels.shape[0]

    # This is where training samples and labels are fed to the graph.

    # These placeholder nodes will be fed a batch of training data at each

    # training step using the {feed_dict} argument to the Run() call below.

    train_data_node = tf.placeholder(

        data_type(),

        shape=(BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, NUM_CHANNELS))

    train_labels_node = tf.placeholder(tf.int64, shape=(BATCH_SIZE,))

    eval_data = tf.placeholder(

        data_type(),

        shape=(EVAL_BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, NUM_CHANNELS))

    # The variables below hold all the trainable weights. They are passed an

    # initial value which will be assigned when we call:

    # {tf.global_variables_initializer().run()}

    conv1_weights = tf.Variable(

        tf.truncated_normal([5, 5, NUM_CHANNELS, 32],  # 5x5 filter, depth 32.

                            stddev=0.1,

                            seed=SEED, dtype=data_type()))

    conv1_biases = tf.Variable(tf.zeros([32], dtype=data_type()))

    conv2_weights = tf.Variable(tf.truncated_normal(

        [5, 5, 32, 64], stddev=0.1,

        seed=SEED, dtype=data_type()))

    conv2_biases = tf.Variable(tf.constant(0.1, shape=[64], dtype=data_type()))

    fc1_weights = tf.Variable(  # fully connected, depth 512.

        tf.truncated_normal([IMAGE_SIZE // 4 * IMAGE_SIZE // 4 * 64, 512],

                            stddev=0.1,

                            seed=SEED,

                            dtype=data_type()))

    fc1_biases = tf.Variable(tf.constant(0.1, shape=[512], dtype=data_type()))

    fc2_weights = tf.Variable(tf.truncated_normal([512, NUM_LABELS],

                                                  stddev=0.1,

                                                  seed=SEED,

                                                  dtype=data_type()))

    fc2_biases = tf.Variable(tf.constant(

        0.1, shape=[NUM_LABELS], dtype=data_type()))

    # We will replicate the model structure for the training subgraph, as well

    # as the evaluation subgraphs, while sharing the trainable parameters.

    def model(data, train=False):

        """The Model definition."""

        # 2D convolution, with 'SAME' padding (i.e. the output feature map has

        # the same size as the input). Note that {strides} is a 4D array whose

        # shape matches the data layout: [image index, y, x, depth].

        conv = tf.nn.conv2d(data,

                            conv1_weights,

                            strides=[1, 1, 1, 1],

                            padding='SAME')

        # Bias and rectified linear non-linearity.

        relu = tf.nn.relu(tf.nn.bias_add(conv, conv1_biases))

        # Max pooling. The kernel size spec {ksize} also follows the layout of

        # the data. Here we have a pooling window of 2, and a stride of 2.

        pool = tf.nn.max_pool(relu,

                              ksize=[1, 2, 2, 1],

                              strides=[1, 2, 2, 1],

                              padding='SAME')

        conv = tf.nn.conv2d(pool,

                            conv2_weights,

                            strides=[1, 1, 1, 1],

                            padding='SAME')

        relu = tf.nn.relu(tf.nn.bias_add(conv, conv2_biases))

        pool = tf.nn.max_pool(relu,

                              ksize=[1, 2, 2, 1],

                              strides=[1, 2, 2, 1],

                              padding='SAME')

        # Reshape the feature map cuboid into a 2D matrix to feed it to the

        # fully connected layers.

        pool_shape = pool.get_shape().as_list()

        reshape = tf.reshape(

            pool,

            [pool_shape[0], pool_shape[1] * pool_shape[2] * pool_shape[3]])

        # Fully connected layer. Note that the '+' operation automatically

        # broadcasts the biases.

        hidden = tf.nn.relu(tf.matmul(reshape, fc1_weights) + fc1_biases)

        # Add a 50% dropout during training only. Dropout also scales

        # activations such that no rescaling is needed at evaluation time.

        if train:

            hidden = tf.nn.dropout(hidden, 0.5, seed=SEED)

        return tf.matmul(hidden, fc2_weights) + fc2_biases

    # Training computation: logits + cross-entropy loss.

    logits = model(train_data_node, True)

    loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(

        labels=train_labels_node, logits=logits))

    # L2 regularization for the fully connected parameters.

    regularizers = (tf.nn.l2_loss(fc1_weights) + tf.nn.l2_loss(fc1_biases) +

                    tf.nn.l2_loss(fc2_weights) + tf.nn.l2_loss(fc2_biases))

    # Add the regularization term to the loss.

    loss += 5e-4 * regularizers

    # Optimizer: set up a variable that's incremented once per batch and

    # controls the learning rate decay.

    batch = tf.Variable(0, dtype=data_type())

    # Decay once per epoch, using an exponential schedule starting at 0.01.

    learning_rate = tf.train.exponential_decay(

        0.01,  # Base learning rate.

        batch * BATCH_SIZE,  # Current index into the dataset.

        train_size,  # Decay step.

        0.95,  # Decay rate.

        staircase=True)

    # Use simple momentum for the optimization.

    optimizer = tf.train.MomentumOptimizer(learning_rate,

                                          0.9).minimize(loss,

                                                        global_step=batch)

    # Predictions for the current training minibatch.

    train_prediction = tf.nn.softmax(logits)

    # Predictions for the test and validation, which we'll compute less often.

    eval_prediction = tf.nn.softmax(model(eval_data))

    # Small utility function to evaluate a dataset by feeding batches of data to

    # {eval_data} and pulling the results from {eval_predictions}.

    # Saves memory and enables this to run on smaller GPUs.

    def eval_in_batches(data, sess):

        """Get all predictions for a dataset by running it in small batches."""

        size = data.shape[0]

        if size < EVAL_BATCH_SIZE:

            logging.error("batch size for evals larger than dataset: %d" % size)

            raise ValueError("batch size for evals larger than dataset: %d" % size)

        predictions = numpy.ndarray(shape=(size, NUM_LABELS), dtype=numpy.float32)

        for begin in xrange(0, size, EVAL_BATCH_SIZE):

            end = begin + EVAL_BATCH_SIZE

            if end <= size:

                predictions[begin:end, :] = sess.run(

                    eval_prediction,

                    feed_dict={eval_data: data[begin:end, ...]})

            else:

                batch_predictions = sess.run(

                    eval_prediction,

                    feed_dict={eval_data: data[-EVAL_BATCH_SIZE:, ...]})

                predictions[begin:, :] = batch_predictions[begin - size:, :]

        return predictions

    # Create a local session to run the training.

    start_time = time.time()

    with tf.Session() as sess:

        # Run all the initializers to prepare the trainable parameters.

        tf.global_variables_initializer().run()

        logging.info('Initialized!')

        print('Initialized!')

        # Loop through training steps.

        for step in xrange(int(num_epochs * train_size) // BATCH_SIZE):

            # Compute the offset of the current minibatch in the data.

            # Note that we could use better randomization across epochs.

            offset = (step * BATCH_SIZE) % (train_size - BATCH_SIZE)

            batch_data = train_data[offset:(offset + BATCH_SIZE), ...]

            batch_labels = train_labels[offset:(offset + BATCH_SIZE)]

            # This dictionary maps the batch data (as a numpy array) to the

            # node in the graph it should be fed to.

            feed_dict = {train_data_node: batch_data,

                        train_labels_node: batch_labels}

            # Run the optimizer to update weights.

            sess.run(optimizer, feed_dict=feed_dict)

            # print some extra information once reach the evaluation frequency

            if step % EVAL_FREQUENCY == 0:

                # fetch some extra nodes' data

                l, lr, predictions = sess.run([loss, learning_rate, train_prediction],

                                              feed_dict=feed_dict)

                elapsed_time = time.time() - start_time

                start_time = time.time()

                logging.info('Step %d (epoch %.2f), %.1f ms' %(step, float(step) * BATCH_SIZE / train_size, 1000 * elapsed_time / EVAL_FREQUENCY))

                print('Step %d (epoch %.2f), %.1f ms' %

                      (step, float(step) * BATCH_SIZE / train_size,

                      1000 * elapsed_time / EVAL_FREQUENCY))

                logging.info('Minibatch loss: %.3f, learning rate: %.6f' % (l, lr))

                print('Minibatch loss: %.3f, learning rate: %.6f' % (l, lr))

                logging.info('Minibatch error: %.1f%%' % error_rate(predictions, batch_labels))

                print('Minibatch error: %.1f%%' % error_rate(predictions, batch_labels))

                logging.info('Validation error: %.1f%%' % error_rate(eval_in_batches(validation_data, sess), validation_labels))

                print('Validation error: %.1f%%' % error_rate(

                    eval_in_batches(validation_data, sess), validation_labels))

                sys.stdout.flush()

        # Finally print the result!

        test_error = error_rate(eval_in_batches(test_data, sess), test_labels)

        logging.info('Test error: %.1f%%' % test_error)

        print('Test error: %.1f%%' % test_error)

        if FLAGS.self_test:

            logging.info('test_error' + test_error)

            print('test_error', test_error)

            assert test_error == 0.0, 'expected 0.0 test_error, got %.2f' % (

                test_error,)

if __name__ == '__main__':

    parser = argparse.ArgumentParser()

    parser.add_argument(

        '--use_fp16',

        default=False,

        help='Use half floats instead of full floats if True.',

        action='store_true')

    parser.add_argument(

        '--self_test',

        default=False,

        action='store_true',

        help='True if running a self test.')

    FLAGS, unparsed = parser.parse_known_args()

    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

這里我在原來的程序基礎(chǔ)上面稍微改了下,因?yàn)槲乙呀?jīng)提前將數(shù)據(jù)下載好了,所以我讓程序直接讀取本機(jī)指定目錄下的訓(xùn)練數(shù)據(jù),同時(shí)增加了日志文件輸出.這是為了在公司的容器云平臺(tái)上測(cè)試獲取容器輸出文件

編寫Dockerfile

我們可以在我們的用戶目錄下,創(chuàng)建一個(gè)空的文件夾,將mnist數(shù)據(jù)集以及程序文件都拷貝進(jìn)這個(gè)文件夾下.其實(shí)數(shù)據(jù)集應(yīng)該是放在數(shù)據(jù)卷中,但是這里為了方便,我直接將訓(xùn)練數(shù)據(jù)打進(jìn)了鏡像中.然后創(chuàng)建Dockerfile,文件內(nèi)容如下


FROM tensorflow/tensorflow:1.9.0-devel-py3

COPY . /home/ll

WORKDIR /home/ll

CMD ['python', 'convolutional.py']

即Dockerfile文件中最后一行表示容器啟動(dòng)的運(yùn)行的命令

build鏡像


docker build -t tf:1.9 .

-t參數(shù)指定鏡像跟tag,最后的.指定了鏡像中的上下文.構(gòu)建完之后使用docker images可以查看多了tf:1.9鏡像

運(yùn)行鏡像

運(yùn)行下面的命令,運(yùn)行上一步構(gòu)建好的鏡像


docker run -it --name test tf:1.9

然后就能夠看到訓(xùn)練的輸出.

image

同時(shí)可以在看一個(gè)連接,進(jìn)入容器,即運(yùn)行下面命令


docker exec -it test /bin/bash

可以看到如下內(nèi)容

image

即看到了cnn_mnist.log的日志輸出文件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嚼酝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竟坛,老刑警劉巖革半,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異流码,居然都是意外死亡又官,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門漫试,熙熙樓的掌柜王于貴愁眉苦臉地迎上來六敬,“玉大人,你說我怎么就攤上這事驾荣⊥夤梗” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵播掷,是天一觀的道長(zhǎng)审编。 經(jīng)常有香客問我,道長(zhǎng)歧匈,這世上最難降的妖魔是什么垒酬? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮件炉,結(jié)果婚禮上勘究,老公的妹妹穿的比我還像新娘。我一直安慰自己斟冕,他們只是感情好口糕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著磕蛇,像睡著了一般景描。 火紅的嫁衣襯著肌膚如雪十办。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天超棺,我揣著相機(jī)與錄音向族,去河邊找鬼。 笑死说搅,一個(gè)胖子當(dāng)著我的面吹牛炸枣,可吹牛的內(nèi)容都是我干的虏等。 我是一名探鬼主播弄唧,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼霍衫!你這毒婦竟也來了候引?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤敦跌,失蹤者是張志新(化名)和其女友劉穎澄干,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柠傍,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡麸俘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惧笛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片从媚。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖患整,靈堂內(nèi)的尸體忽然破棺而出拜效,到底是詐尸還是另有隱情,我是刑警寧澤各谚,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布紧憾,位于F島的核電站,受9級(jí)特大地震影響昌渤,放射性物質(zhì)發(fā)生泄漏赴穗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一膀息、第九天 我趴在偏房一處隱蔽的房頂上張望望抽。 院中可真熱鬧,春花似錦履婉、人聲如沸煤篙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辑奈。三九已至苛茂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鸠窗,已是汗流浹背妓羊。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稍计,地道東北人躁绸。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像臣嚣,于是被迫代替她去往敵國(guó)和親净刮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容