{
  "id": 12924,
  "title": "Poisson Process' Solution",
  "url": "/competitions/datasciencebowl/writeups/poisson-process-poisson-process-solution",
  "author_name": "",
  "post_date": "2015-03-19T19:02:58.653Z",
  "votes": 9,
  "comment_count": 4,
  "views": 2539,
  "content": "<p>This is just a quick overview for those curious about our solution. &nbsp;It seems quite simple compared to the other top two teams. &nbsp;I would like to make a blog post of how I approached this competition since this was my first time using CNNs, and my experience may be valuable for others as I was rapidly improving my methods towards the end of the competition. Of course I have also extensively followed the progress of neural networks since 2012's ImageNet competition, which helped a lot.</p>\n<p><strong>Why Spatially Sparse Networks?</strong></p>\n<p>I think this was probably a large advantage in this competition. &nbsp;Most of these images are simply white background. &nbsp;In fact I believe only 15% of the pixels had initial activations in my networks. &nbsp;This architecture allowed for a lot of flexibility in data augmentation since you can have really wide input fields and not greatly hurt performance.</p>\n<p><strong>Network Architecture</strong></p>\n<p>The architectures are mostly based off of templates for&nbsp;<a href=\"http://www2.warwick.ac.uk/fac/sci/statistics/staff/academic-research/graham/sparsecnn.pdf\">Spatially Sparse Networks</a>&nbsp;with varying the number of layers between max pools.</p>\n<p>I tried 27 layer 2x2 convolutional filters with 5 2x2 Max Pooling layers. &nbsp;I believe that a 3x3 with 2 stride would have produced better results. &nbsp;I also had 18 layers with wider nets and 22 layers. &nbsp;All worked very well and produced single network scores of 0.618 - 0.625. &nbsp;Most networks had 4-5 max pooling layers.</p>\n<p>I eventually settled on a network similar to VGG with 3x3 convolutional filters. &nbsp;This was a shorter network with only 14 layers. These scored from 0.610 to 0.620. &nbsp;They were also moderately small. &nbsp;My networks were 3 million to 11 million parameters in size with moderate drop out. (0.2)</p>\n<p>Dr. Ben Graham was able to achieve a single network score of <strong>0.599</strong>&nbsp;with a network consisting of 12 Fractional Max Pooling layers. &nbsp;(see&nbsp;<a href=\"http://www2.warwick.ac.uk/fac/sci/statistics/staff/academic-research/graham/fmp.pdf\">FMP Paper</a>) He also had a network with 0.608 which used 3x3 max pooling layers with a stride of 2.</p>\n<p><strong>Data Augmentation</strong></p>\n<p>Everything was done in real time. &nbsp;Dr. Ben Graham used affine transformations and I was using perspective transformations. &nbsp;The real key is that pretty much anything that doesn't change classes is fair game. &nbsp;If you look at the test data, many classes are heavily biased to certain orientations. &nbsp;However, it is best not to try and match these biases.</p>\n<p>Too much of a good thing can be bad. &nbsp;It was good to add small random variations in scaling, but if you increased it too much then the score was greatly hurt. &nbsp;I read somewhere that CNNs have problems dealing with data at different scales. It seems that this may be somewhat true.</p>\n<p>Since this was a spatially sparse network I found that dividing the largest dimension of each input image by 2.5 and adding 30 produced much better results than simply scaling the largest dimension to 80 or 100 or something similar.</p>\n<p><strong>Encoding</strong></p>\n<p>I have no idea how much the methods I used here really helped. &nbsp;I thresholded out any pixels &gt; 252. &nbsp;I then calculated the global mean and standard deviation of the training set, and each individual image over the remaining pixels. &nbsp;I also calculated a windowed (11x11) mean and standard deviation for each pixel. &nbsp;Those were combined to form 3 channels. &nbsp;I added a forth channel which used the global mean and image standard deviation.</p>\n<p>I really should have explored how I encoded the images more as I believe this method caused several classes to be very difficult to predict properly. (see below)</p>\n<p>Ben used a different method which can be seen in his code at his page.</p>\n<p><strong>Problem Areas</strong></p>\n<p>I believe that the encoding method I used made several classes very difficult for my network to predict properly. &nbsp;This problem did not appear in Ben's networks.</p>\n<p>Artifact_Edges was predicted as 2.4% of my total aggregated classes. &nbsp;It should have been closer to 0.56% (Based on training data). &nbsp;Protist_dark_center was predicted as 1.14% of my total aggregated classes. It should have been closer to 0.36%. These two classes were very large outliers for me.</p>\n<p>Our final ensemble was a little better with these classes, but this definitely hurt our final score.</p>\n<p><strong>Ensemble</strong></p>\n<p>Our final ensemble had 15ish&nbsp;networks with Dr. Graham's best net being counted twice. &nbsp;However, an ensemble of 5 networks reached 99.8% of the best score.</p>\n<p>I am really amazed out how you can add a network with a score of 0.63 and still see an improvement in score.&nbsp;</p>\n<p><strong>Some Things Different</strong></p>\n<p>Sometimes training really deep nets with dropout can make convergence painfully slow at the start. &nbsp;So I implemented a gradual drop out where I start at 0 drop out and introduce more and more drop out as the score improves on the training set. &nbsp;Usually by the 10-20th epoch I have reached maximum dropout across all layers. This doesn't seem to hurt final performance of the network.</p>\n<p><strong>Some Things Bad</strong></p>\n<p>To save time I tried to take partially trained networks and then change the input variables to create a new net. &nbsp;This was not a good idea.</p>\n<p><strong>Last Words</strong></p>\n<p>I haven't consulted with Dr. Graham before writing this so he may have something more to add.</p>\n<p>If you have any questions I will be glad to try and answer them.</p>",
  "messages": [
    {
      "id": "67269",
      "postDate": "03/19/2015 19:02:58",
      "content": "<p>This is just a quick overview for those curious about our solution. &nbsp;It seems quite simple compared to the other top two teams. &nbsp;I would like to make a blog post of how I approached this competition since this was my first time using CNNs, and my experience may be valuable for others as I was rapidly improving my methods towards the end of the competition. Of course I have also extensively followed the progress of neural networks since 2012's ImageNet competition, which helped a lot.</p>\n<p><strong>Why Spatially Sparse Networks?</strong></p>\n<p>I think this was probably a large advantage in this competition. &nbsp;Most of these images are simply white background. &nbsp;In fact I believe only 15% of the pixels had initial activations in my networks. &nbsp;This architecture allowed for a lot of flexibility in data augmentation since you can have really wide input fields and not greatly hurt performance.</p>\n<p><strong>Network Architecture</strong></p>\n<p>The architectures are mostly based off of templates for&nbsp;<a href=\"http://www2.warwick.ac.uk/fac/sci/statistics/staff/academic-research/graham/sparsecnn.pdf\">Spatially Sparse Networks</a>&nbsp;with varying the number of layers between max pools.</p>\n<p>I tried 27 layer 2x2 convolutional filters with 5 2x2 Max Pooling layers. &nbsp;I believe that a 3x3 with 2 stride would have produced better results. &nbsp;I also had 18 layers with wider nets and 22 layers. &nbsp;All worked very well and produced single network scores of 0.618 - 0.625. &nbsp;Most networks had 4-5 max pooling layers.</p>\n<p>I eventually settled on a network similar to VGG with 3x3 convolutional filters. &nbsp;This was a shorter network with only 14 layers. These scored from 0.610 to 0.620. &nbsp;They were also moderately small. &nbsp;My networks were 3 million to 11 million parameters in size with moderate drop out. (0.2)</p>\n<p>Dr. Ben Graham was able to achieve a single network score of <strong>0.599</strong>&nbsp;with a network consisting of 12 Fractional Max Pooling layers. &nbsp;(see&nbsp;<a href=\"http://www2.warwick.ac.uk/fac/sci/statistics/staff/academic-research/graham/fmp.pdf\">FMP Paper</a>) He also had a network with 0.608 which used 3x3 max pooling layers with a stride of 2.</p>\n<p><strong>Data Augmentation</strong></p>\n<p>Everything was done in real time. &nbsp;Dr. Ben Graham used affine transformations and I was using perspective transformations. &nbsp;The real key is that pretty much anything that doesn't change classes is fair game. &nbsp;If you look at the test data, many classes are heavily biased to certain orientations. &nbsp;However, it is best not to try and match these biases.</p>\n<p>Too much of a good thing can be bad. &nbsp;It was good to add small random variations in scaling, but if you increased it too much then the score was greatly hurt. &nbsp;I read somewhere that CNNs have problems dealing with data at different scales. It seems that this may be somewhat true.</p>\n<p>Since this was a spatially sparse network I found that dividing the largest dimension of each input image by 2.5 and adding 30 produced much better results than simply scaling the largest dimension to 80 or 100 or something similar.</p>\n<p><strong>Encoding</strong></p>\n<p>I have no idea how much the methods I used here really helped. &nbsp;I thresholded out any pixels &gt; 252. &nbsp;I then calculated the global mean and standard deviation of the training set, and each individual image over the remaining pixels. &nbsp;I also calculated a windowed (11x11) mean and standard deviation for each pixel. &nbsp;Those were combined to form 3 channels. &nbsp;I added a forth channel which used the global mean and image standard deviation.</p>\n<p>I really should have explored how I encoded the images more as I believe this method caused several classes to be very difficult to predict properly. (see below)</p>\n<p>Ben used a different method which can be seen in his code at his page.</p>\n<p><strong>Problem Areas</strong></p>\n<p>I believe that the encoding method I used made several classes very difficult for my network to predict properly. &nbsp;This problem did not appear in Ben's networks.</p>\n<p>Artifact_Edges was predicted as 2.4% of my total aggregated classes. &nbsp;It should have been closer to 0.56% (Based on training data). &nbsp;Protist_dark_center was predicted as 1.14% of my total aggregated classes. It should have been closer to 0.36%. These two classes were very large outliers for me.</p>\n<p>Our final ensemble was a little better with these classes, but this definitely hurt our final score.</p>\n<p><strong>Ensemble</strong></p>\n<p>Our final ensemble had 15ish&nbsp;networks with Dr. Graham's best net being counted twice. &nbsp;However, an ensemble of 5 networks reached 99.8% of the best score.</p>\n<p>I am really amazed out how you can add a network with a score of 0.63 and still see an improvement in score.&nbsp;</p>\n<p><strong>Some Things Different</strong></p>\n<p>Sometimes training really deep nets with dropout can make convergence painfully slow at the start. &nbsp;So I implemented a gradual drop out where I start at 0 drop out and introduce more and more drop out as the score improves on the training set. &nbsp;Usually by the 10-20th epoch I have reached maximum dropout across all layers. This doesn't seem to hurt final performance of the network.</p>\n<p><strong>Some Things Bad</strong></p>\n<p>To save time I tried to take partially trained networks and then change the input variables to create a new net. &nbsp;This was not a good idea.</p>\n<p><strong>Last Words</strong></p>\n<p>I haven't consulted with Dr. Graham before writing this so he may have something more to add.</p>\n<p>If you have any questions I will be glad to try and answer them.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "67280",
      "postDate": "03/19/2015 19:51:57",
      "content": "<p>Nice and simple solution, thanks for sharing!</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "67323",
      "postDate": "03/19/2015 22:21:41",
      "content": "<p>Great writeup!</p>\n<p>I was wondering why none of the other solutions used sparse nets, it seems like such a perfect match for this data. With ~80% of the image space being more or less blank, a standard convnet will waste a LOT of cycles on doing nothing, basically.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "67334",
      "postDate": "03/19/2015 23:22:40",
      "content": "<p>This is really, really interesting! Thanks for the write-up! It's also quite different from what we came up with, so chances are that combining some of these ideas might improve things further.</p>\n<p>Also, massive respect to you if this is really your first time working with convnets. Amazing work!</p>\n<p>[quote=Ryan Munion;67269]Dr. Ben Graham was able to achieve a single network score of 0.599 with a network consisting of 12 Fractional Max Pooling layers.[/quote]</p>\n<p>Is this a leaderboard score? Was any averaging of predictions (i.e. test-time augmentation) done to arrive at this score? Because that's pretty impressive. I think the lowest we got for a single model (not counting models trained with pseudo-labeling) was about 0.607, and this was the score with test-time augmentation (i.e. each prediction was actually an average of 70 predictions).</p>\n<p>[quote]Too much of a good thing can be bad. It was good to add small random variations in scaling, but if you increased it too much then the score was greatly hurt. I read somewhere that CNNs have problems dealing with data at different scales. It seems that this may be somewhat true.[/quote]</p>\n<p>How large were the scale variations in the end? We ended up jittering the scale of the images between 1/1.6 and 1.6 (after initial size-based rescaling), which I found pretty extreme, but it seemed to help.</p>\n<p>[quote]Since this was a spatially sparse network I found that dividing the largest dimension of each input image by 2.5 and adding 30 produced much better results than simply scaling the largest dimension to 80 or 100 or something similar.[/quote]</p>\n<p>So if I understand this correctly, your rescaling approximately preserved the relative sizes of the organisms?</p>\n<p>[quote]Ben used a different method which can be seen in his code at his page.[/quote]</p>\n<p>Is this code available online anywhere yet? I can't seem to find it but I'm very curious :)</p>\n<p>[quote]Our final ensemble had 15ish networks with Dr. Graham's best net being counted twice. However, an ensemble of 5 networks reached 99.8% of the best score.[/quote]</p>\n<p>If your single best network achieved 0.599 on the leaderboard I'm somewhat surprised that the ensemble score isn't better, to be honest! Did you just average the predictions of all the networks together?</p>\n<p>[quote]I am really amazed out how you can add a network with a score of 0.63 and still see an improvement in score.[/quote]</p>\n<p>We had the same experience. We were sometimes very surprised by the models that would be selected by the ensembling procedure.</p>\n<p>[quote]Sometimes training really deep nets with dropout can make convergence painfully slow at the start. So I implemented a gradual drop out where I start at 0 drop out and introduce more and more drop out as the score improves on the training set. Usually by the 10-20th epoch I have reached maximum dropout across all layers. This doesn't seem to hurt final performance of the network.[/quote]</p>\n<p>This is an excellent idea. We ended up not using dropout in any of the convolutional layers because it tended to slow down training too much. The few times we attempted to use it, the effect probably wasn't strong enough to make a difference.</p>",
      "rawMarkdown": "",
      "votes": null
    },
    {
      "id": "67342",
      "postDate": "03/20/2015 00:32:33",
      "content": "<p>Great questions! &nbsp;And yes, it is my first time though I do computer vision work for a living. &nbsp;I spent the first half of the competition trying to get a breakthrough on semisupervised learning on Cifar 100 data set. &nbsp;I learned that coming up with breakthroughs is&nbsp;hard!</p>\n<p>[quote]</p>\n<p>Is this a leaderboard score? Was any averaging of predictions (i.e. test-time augmentation) done to arrive at this score? Because that's pretty impressive. I think the lowest we got for a single model (not counting models trained with pseudo-labeling) was about 0.607, and this was the score with test-time augmentation (i.e. each prediction was actually an average of 70 predictions).</p>\n<p>[/quote]</p>\n<p>It was a leaderboard score! &nbsp;He submitted it 2 hours before the end of the competition. &nbsp;It was a test time augmentation over 20-30 tests. All of our nets used test time augmentation. &nbsp;However, our&nbsp;method&nbsp;differed from yours in that I just did random transformations of the test data exactly like the training data.</p>\n<p>He used pseudo random overlapping fractional max pooling layers. &nbsp;Previously, the same net scored 0.608 I think. &nbsp;Unfortunately, substituting the net predictions didn't help our overall score very much.</p>\n<p>None of our nets used soft labeling techniques, though I did explore such methods early on.</p>\n<p>[quote]How large were the scale variations in the end? We ended up jittering the scale of the images between 1/1.6 and 1.6 (after initial size-based rescaling), which I found pretty extreme, but it seemed to help.[/quote]</p>\n<p>I believe they were 1/2.2 to 2.2. &nbsp;Some of this could be the size of the networks I was working with at the time. &nbsp;I ended up with only doing +- 30% on most of my networks.</p>\n<p>[quote]So if I understand this correctly, your rescaling approximately preserved the relative sizes of the organisms?[/quote]</p>\n<p>Yes. &nbsp;It helped quite a bit. &nbsp;But it was horrible use of memory, because if I randomly selected several large images in a single batch my application would crash. &nbsp;So I had to reduce the batch size to 20.</p>\n<p>[quote]</p>\n<p>Is this code available online anywhere yet? I can't seem to find it but I'm very curious :)</p>\n<p>[/quote]</p>\n<p>His FMP work is not yet available (It will be), but he has his spatially sparse code available which shows his augmentations.</p>\n<p>[quote]</p>\n<p>If your single best network achieved 0.599 on the leaderboard I'm somewhat surprised that the ensemble score isn't better, to be honest! Did you just average the predictions of all the networks together?[/quote]</p>\n<p>Yes, we did just average the scores together. &nbsp;To count twice I simply dropped a copy of the prediction file into my combine directory. &nbsp;It was very crude, but I was running out of time. &nbsp;I think the biggest problem was that I was greatly over predicting artifact_edges and protist_dark_center. All of my networks were biased in this same manner. &nbsp;The local normalization I used was probably greatly over exaggerating the background noise in many of the images.&nbsp;</p>\n<p>I did try replacing my predictions for those classes with Ben's predictions with five minutes left in the competition, but it was too little too late.</p>",
      "rawMarkdown": "",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 67280,
      "author_name": "oldufo",
      "author_url": "",
      "post_date": "03/19/2015 19:51:57",
      "content": "<p>Nice and simple solution, thanks for sharing!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 67323,
      "author_name": "nicolaykorslund",
      "author_url": "",
      "post_date": "03/19/2015 22:21:41",
      "content": "<p>Great writeup!</p>\n<p>I was wondering why none of the other solutions used sparse nets, it seems like such a perfect match for this data. With ~80% of the image space being more or less blank, a standard convnet will waste a LOT of cycles on doing nothing, basically.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 67334,
      "author_name": "sedielem",
      "author_url": "",
      "post_date": "03/19/2015 23:22:40",
      "content": "<p>This is really, really interesting! Thanks for the write-up! It's also quite different from what we came up with, so chances are that combining some of these ideas might improve things further.</p>\n<p>Also, massive respect to you if this is really your first time working with convnets. Amazing work!</p>\n<p>[quote=Ryan Munion;67269]Dr. Ben Graham was able to achieve a single network score of 0.599 with a network consisting of 12 Fractional Max Pooling layers.[/quote]</p>\n<p>Is this a leaderboard score? Was any averaging of predictions (i.e. test-time augmentation) done to arrive at this score? Because that's pretty impressive. I think the lowest we got for a single model (not counting models trained with pseudo-labeling) was about 0.607, and this was the score with test-time augmentation (i.e. each prediction was actually an average of 70 predictions).</p>\n<p>[quote]Too much of a good thing can be bad. It was good to add small random variations in scaling, but if you increased it too much then the score was greatly hurt. I read somewhere that CNNs have problems dealing with data at different scales. It seems that this may be somewhat true.[/quote]</p>\n<p>How large were the scale variations in the end? We ended up jittering the scale of the images between 1/1.6 and 1.6 (after initial size-based rescaling), which I found pretty extreme, but it seemed to help.</p>\n<p>[quote]Since this was a spatially sparse network I found that dividing the largest dimension of each input image by 2.5 and adding 30 produced much better results than simply scaling the largest dimension to 80 or 100 or something similar.[/quote]</p>\n<p>So if I understand this correctly, your rescaling approximately preserved the relative sizes of the organisms?</p>\n<p>[quote]Ben used a different method which can be seen in his code at his page.[/quote]</p>\n<p>Is this code available online anywhere yet? I can't seem to find it but I'm very curious :)</p>\n<p>[quote]Our final ensemble had 15ish networks with Dr. Graham's best net being counted twice. However, an ensemble of 5 networks reached 99.8% of the best score.[/quote]</p>\n<p>If your single best network achieved 0.599 on the leaderboard I'm somewhat surprised that the ensemble score isn't better, to be honest! Did you just average the predictions of all the networks together?</p>\n<p>[quote]I am really amazed out how you can add a network with a score of 0.63 and still see an improvement in score.[/quote]</p>\n<p>We had the same experience. We were sometimes very surprised by the models that would be selected by the ensembling procedure.</p>\n<p>[quote]Sometimes training really deep nets with dropout can make convergence painfully slow at the start. So I implemented a gradual drop out where I start at 0 drop out and introduce more and more drop out as the score improves on the training set. Usually by the 10-20th epoch I have reached maximum dropout across all layers. This doesn't seem to hurt final performance of the network.[/quote]</p>\n<p>This is an excellent idea. We ended up not using dropout in any of the convolutional layers because it tended to slow down training too much. The few times we attempted to use it, the effect probably wasn't strong enough to make a difference.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 67342,
      "author_name": "iamthep",
      "author_url": "",
      "post_date": "03/20/2015 00:32:33",
      "content": "<p>Great questions! &nbsp;And yes, it is my first time though I do computer vision work for a living. &nbsp;I spent the first half of the competition trying to get a breakthrough on semisupervised learning on Cifar 100 data set. &nbsp;I learned that coming up with breakthroughs is&nbsp;hard!</p>\n<p>[quote]</p>\n<p>Is this a leaderboard score? Was any averaging of predictions (i.e. test-time augmentation) done to arrive at this score? Because that's pretty impressive. I think the lowest we got for a single model (not counting models trained with pseudo-labeling) was about 0.607, and this was the score with test-time augmentation (i.e. each prediction was actually an average of 70 predictions).</p>\n<p>[/quote]</p>\n<p>It was a leaderboard score! &nbsp;He submitted it 2 hours before the end of the competition. &nbsp;It was a test time augmentation over 20-30 tests. All of our nets used test time augmentation. &nbsp;However, our&nbsp;method&nbsp;differed from yours in that I just did random transformations of the test data exactly like the training data.</p>\n<p>He used pseudo random overlapping fractional max pooling layers. &nbsp;Previously, the same net scored 0.608 I think. &nbsp;Unfortunately, substituting the net predictions didn't help our overall score very much.</p>\n<p>None of our nets used soft labeling techniques, though I did explore such methods early on.</p>\n<p>[quote]How large were the scale variations in the end? We ended up jittering the scale of the images between 1/1.6 and 1.6 (after initial size-based rescaling), which I found pretty extreme, but it seemed to help.[/quote]</p>\n<p>I believe they were 1/2.2 to 2.2. &nbsp;Some of this could be the size of the networks I was working with at the time. &nbsp;I ended up with only doing +- 30% on most of my networks.</p>\n<p>[quote]So if I understand this correctly, your rescaling approximately preserved the relative sizes of the organisms?[/quote]</p>\n<p>Yes. &nbsp;It helped quite a bit. &nbsp;But it was horrible use of memory, because if I randomly selected several large images in a single batch my application would crash. &nbsp;So I had to reduce the batch size to 20.</p>\n<p>[quote]</p>\n<p>Is this code available online anywhere yet? I can't seem to find it but I'm very curious :)</p>\n<p>[/quote]</p>\n<p>His FMP work is not yet available (It will be), but he has his spatially sparse code available which shows his augmentations.</p>\n<p>[quote]</p>\n<p>If your single best network achieved 0.599 on the leaderboard I'm somewhat surprised that the ensemble score isn't better, to be honest! Did you just average the predictions of all the networks together?[/quote]</p>\n<p>Yes, we did just average the scores together. &nbsp;To count twice I simply dropped a copy of the prediction file into my combine directory. &nbsp;It was very crude, but I was running out of time. &nbsp;I think the biggest problem was that I was greatly over predicting artifact_edges and protist_dark_center. All of my networks were biased in this same manner. &nbsp;The local normalization I used was probably greatly over exaggerating the background noise in many of the images.&nbsp;</p>\n<p>I did try replacing my predictions for those classes with Ben's predictions with five minutes left in the competition, but it was too little too late.</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "67269": "",
    "67280": "",
    "67323": "",
    "67334": "",
    "67342": ""
  },
  "source": "existing_discussion",
  "complete": true,
  "competition_id": 3978,
  "competition_slug": "datasciencebowl",
  "team_id": 153620,
  "solution_url": "/competitions/datasciencebowl/writeups/poisson-process-poisson-process-solution"
}